home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / t3dlib_src_r43.lha / read.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-02  |  88.1 KB  |  2,643 lines

  1. /* read.c - read a TTDDD file and fill the structures
  2.  *        - written by Glenn M. Lewis - 7/19/91
  3.  *        - Altered for Imagine 3.0 support - Rob Hounsell - Sept.94
  4.  */
  5.  
  6. static char rcs_id[] = "$Id: read.c,v 1.34 1995/02/01 22:21:43 glewis Exp glewis $";
  7.  
  8. #include <stdio.h>
  9. #include <ctype.h>
  10. #include <sys/types.h>
  11. #include "t3dlib.h"
  12. #ifdef __STDC__
  13. #include <stdlib.h>
  14. #include <strings.h>
  15. #include "read_protos.h"
  16. #endif
  17.  
  18. static void process_INFO();
  19. static void process_OBJ();
  20. static void process_ISTG();
  21. static OBJECT *process_EXTR();
  22. static void process_DESC();
  23. static OBJECT *process_MXTR();
  24. static void desc_copy();
  25. static void malloc_arrays();
  26. extern int verbose_flag;
  27. extern int already_read_header;            /* A hack to include characters */
  28. extern unsigned char header_storage[];    /* that were already read in */
  29. extern void insert_into_sorted_list();
  30.  
  31. #define MAXLINE 1024
  32. #define get_UBYTE    (UBYTE)get_num
  33. #define get_UWORD    (UWORD)get_num
  34. #define get_ULONG    (ULONG)get_num
  35.  
  36. static char strin[MAXLINE+1], ps[MAXLINE+1];
  37. static UBYTE defclst[3], defrlst[3], deftlst[3], defspc1[3];
  38.  
  39. /* Here are a few necessary utilities */
  40.  
  41. static void warn(curline)
  42. int curline;
  43. {
  44.     fprintf(stderr, "WARNING: Line %d: ", curline);
  45. }
  46.  
  47. static void parse_effect_data(name)    
  48. register char *name;
  49. {
  50.     register char *c = &strin[0];
  51.     register int i;
  52.     int quote = 0;
  53.  
  54.     /* get all chars in string, skipping first and last quote */
  55.  
  56.     while (*c==' ') c++;        /* Skip over leading spaces */
  57.     for (i=0; *c; i++,c++) {
  58.         if (*c == '\"') {            /* Chop off quotes, ignore spaces */
  59.             if (!quote) {  /* first quote */
  60.                 quote=1;
  61.                 i--;                    /* Don't want i to increment */
  62.                 continue;
  63.             } else
  64.           /* Check for Second quote at END of string.  Stop reading string */
  65.             if (c[1] == '\0') break;
  66.         } 
  67.         *name++ = *c;    
  68.     }
  69.     *name = '\0';    /* Truncate the puppy */
  70.     /* Now, delete the command from 'strin' */
  71.     while (*c && *c!=' ') c++;    /* Skip the end of the command */
  72.     while (*c==' ') c++;        /* Skip mid-word spacing */
  73.     strcpy(strin, c);            /* Chop off front of line */
  74. }
  75.  
  76. static void parse_word(name, lim, up)    /* Get next word, optionally limit # of chars */
  77. register char *name;
  78. int lim, up;
  79. {
  80.     register char *c = &strin[0];
  81.     register int i;
  82.     int quote = 0;
  83.  
  84.     while (*c==' ') c++;        /* Skip over leading spaces */
  85.     for (i=0; *c; i++,c++) {
  86.         if (lim && i>=lim) break;    /* No more characters desired */
  87.         if (*c == '\"') {            /* Chop off quotes, ignore spaces */
  88.             if (quote) break;        /* Second quote.  Stop reading string */
  89.             quote=1;
  90.             i--;                    /* Don't want i to increment */
  91.             continue;
  92.         }
  93.         if (up && !quote && islower(*c)) *name++ = toupper(*c);
  94.         else {
  95.             if (!quote && *c==' ') break;    /* End of the line */
  96.             *name++ = *c;            /* Don't modify original case */
  97.         }
  98.     }
  99.     *name = '\0';    /* Truncate the puppy */
  100.     /* Now, delete the command from 'strin' */
  101.     while (*c && *c!=' ') c++;    /* Skip the end of the command */
  102.     while (*c==' ') c++;        /* Skip mid-word spacing */
  103.     strcpy(strin, c);            /* Chop off front of line */
  104. }
  105.  
  106. static int get_line(strin, w)
  107. register char *strin;
  108. WORLD *w;
  109. {
  110.     static int comment = 0;
  111.     int quote = 0, start;
  112.     register char *c;
  113.  
  114. GET_MORE:
  115.     if (comment) start = 0; else start = -1;
  116.     if (fgets(&strin[already_read_header], MAXLINE, w->inp) == NULL) {
  117.         already_read_header = 0;
  118.         if (comment)
  119.         fprintf(stderr, "WARNING: Line %d: Unterminated comment.\n",w->cur_line);
  120.         return(0);    /* EOF */
  121.     }
  122.     already_read_header = 0;
  123.     w->cur_line++;
  124.     for (c=strin; *c; c++) {
  125.         if (*c=='/' && c[1]=='*') {            /* Begin of comment */
  126.             if (!quote) {
  127.                 if (!comment++) {            /* First comment */
  128.                     start = (int)(c-strin);
  129.                 }
  130.             }
  131.         } else
  132.         if (*c=='*' && c[1]=='/') {            /* End of comment */
  133.             if (!quote) {
  134.                 comment--;
  135.                 if (comment<0) {
  136.                     fprintf(stderr, "ERROR!  '*/' before '/*'\n*** ABORT ***\n");
  137.                     exit(20);
  138.                 }
  139.                 if (!comment) {                /* Chop off front of line */
  140.                     strcpy(strin, c+2);
  141.                     c = strin-1;            /* Pointer will increment */
  142.                 }
  143.             }
  144.         } else
  145.         if (*c=='%') {                        /* Line comment */
  146.             if (!(quote || comment)) {
  147.                 *c = '\0';                    /* Terminate line */
  148.                 break;
  149.             }
  150.         } else
  151.  
  152.     /* The SPFX line contains uuencoded information, including quotes!   */
  153.     /* So, don't clear the quote flag unless the found quote is followed */
  154.     /* by either a space or a newline character. Spaces are not found    */
  155.     /* in a uuencoded string.                                            */
  156.  
  157.         if ((*c =='\"') && (!quote)) {    /* Starting Quote */
  158.             if (!comment) quote=1-quote;    /* Toggle flag */
  159.         } else
  160.         if ((*c =='\"') && ((c[1] == ' ') || (c[1] == '\n'))) {    /* End Quote */
  161.             if (!comment) quote=1-quote;    /* Toggle flag */
  162.         } else
  163.         if (*c == '\t') *c = ' ';            /* Change tabs to spaces */
  164.         else
  165.         if (!quote && (*c=='[' || *c==']' || *c=='=')) *c = ' ';
  166.         if (*c == '\n') { *c = '\0'; break; }
  167.     }
  168.     if (comment) strin[start] = '\0';        /* Chop off comment */
  169. /* Skip leading white space to see if this line contains anything */
  170.     for (c=strin; *c==' '; c++) ;
  171.     if (!*c) goto GET_MORE;
  172.     return(1);
  173. }
  174.  
  175. static int valid_num;
  176.  
  177. static long get_num()
  178. {
  179.     long val = 0;
  180.     char neg = ' ';
  181.     register char *c = &strin[0];
  182.  
  183.     valid_num = 0;
  184.     while (*c == ' ') c++;        /* Skip leading space */
  185.     if (*c == '-') neg = *c++;    /* Save the negation  */
  186.     if (!isdigit(*c)) return(0L);
  187.     while (*c && isdigit(*c))
  188.         val = (val*10) + (*c++ - '0');
  189.     while (*c == ' ') c++;        /* Skip trailing space */
  190.     strcpy(strin, c);            /* Chop off number */
  191.     valid_num = 1;
  192.     return((neg=='-' ? -val : val));
  193. }
  194.  
  195. static int valid_FRACT;
  196.  
  197. static double get_FRACT()
  198. {
  199.     register long whole, expo;
  200.     register char *s = &strin[0];
  201.     char neg=' ', negexp=' ';
  202.     double f, frac, place;
  203.  
  204.     valid_FRACT = 0;
  205.     whole = expo = 0;
  206.     while (*s == ' ') s++;
  207.     if (*s == '-') neg = *s++;
  208.     if (!isdigit(*s) && *s!='.') return(0L);    /* Invalid FRACT */
  209.     while (*s && isdigit(*s))        /* Handle float before decimal point */
  210.         whole = (whole * 10) + (*s++ - '0');
  211.     if (*s == '.') {        /* Handle float after decimal point */
  212.         s++;
  213.         frac = 0.0;
  214.         for (place=10.0; *s && isdigit(*s); place*=10.0)
  215.             frac +=  (*s++ - '0')/place;
  216.         f = (double)whole + frac;
  217.     } else f = (double)whole;
  218.     if (*s == 'e' || *s == 'E') {    /* Support exponential notation */
  219.         s++;
  220.         if (*s=='-' || *s=='+') negexp = *s++;
  221.         while (*s && isdigit(*s)) expo = (expo*10) + (*s++ - '0');
  222.         if (negexp=='-')    while (expo--) f/=10.0;
  223.         else                while (expo--) f*=10.0;
  224.     }
  225.     while (*s == ' ') s++;
  226.     strcpy(strin, s);
  227.     valid_FRACT = 1;
  228.     return((neg=='-' ? -f : f));
  229. }
  230.  
  231. static void stage_RGB(st)
  232. XYZ_st *st;
  233. {
  234.     register char *c = &strin[0];
  235.     register int i, flag, cnt;
  236.  
  237.     flag = 0;    /* If they use 'R','G', or 'B', they must continue to use it */
  238.     /* On the other hand, if they give only a single parameter, then it applies to all */
  239.     cnt = 0;
  240.     for (i=0; i<3; i++) {
  241.         if (*c=='r' || *c=='R')        /* If !valid, it's an ERROR! */
  242.         { *c=' '; st->x = get_FRACT(); if (valid_FRACT) flag=1; }
  243.         else
  244.         if (*c=='g' || *c=='G')
  245.         { *c=' '; st->y = get_FRACT(); if (valid_FRACT) flag=1; }
  246.         else
  247.         if (*c=='b' || *c=='B')
  248.         { *c=' '; st->z = get_FRACT(); if (valid_FRACT) flag=1; }
  249.         else if (!flag) {
  250.             if (i==0)        st->x = get_FRACT();
  251.             else if (i==1)    st->y = get_FRACT();
  252.             else            st->z = get_FRACT();
  253.             if (valid_FRACT) cnt++;
  254.         }
  255.     }
  256.     if (!flag && cnt==1) {     /* Copy value into other two elements */
  257.         st->y = st->z = st->x;
  258.     }
  259. }
  260.  
  261. static void stuff_XYZ(st)
  262. XYZ_st *st;
  263. {
  264.     register char *c = &strin[0];
  265.     register int i, flag, cnt;
  266.  
  267.     flag = 0;    /* If they use 'X','Y', or 'Z', they must continue to use it */
  268.     /* On the other hand, if they give only a single parameter, then it applies to all */
  269.     cnt = 0;
  270.     for (i=0; i<3; i++) {
  271.         if (*c=='x' || *c=='X')        /* If !valid, it's an ERROR! */
  272.         { *c=' '; st->x = get_FRACT(); if (valid_FRACT) flag=1; }
  273.         else
  274.         if (*c=='y' || *c=='Y')
  275.         { *c=' '; st->y = get_FRACT(); if (valid_FRACT) flag=1; }
  276.         else
  277.         if (*c=='z' || *c=='Z')
  278.         { *c=' '; st->z = get_FRACT(); if (valid_FRACT) flag=1; }
  279.         else if (!flag) {
  280.             if (i==0)        st->x = get_FRACT();
  281.             else if (i==1)    st->y = get_FRACT();
  282.             else            st->z = get_FRACT();
  283.             if (valid_FRACT) cnt++;
  284.         }
  285.     }
  286.     if (!flag && cnt==1) {     /* Copy value into other two elements */
  287.         st->y = st->z = st->x;
  288.     }
  289. }
  290.  
  291. static void stuff_RGB(st)
  292. RGB_st *st;
  293. {
  294.     register char *c = &strin[0];
  295.     register int i, flag, cnt;
  296.  
  297.     flag = 0;    /* If they use 'R','G', or 'B', they must continue to use it */
  298.     /* On the other hand, if they give only a single parameter, then it applies to all */
  299.     cnt = 0;
  300.     for (i=0; i<3; i++) {
  301.         if (*c=='r' || *c=='R')        /* If !valid, it's an ERROR! */
  302.         { *c=' '; st->r = get_UBYTE(); if (valid_num) flag=1; }
  303.         else
  304.         if (*c=='g' || *c=='G')
  305.         { *c=' '; st->g = get_UBYTE(); if (valid_num) flag=1; }
  306.         else
  307.         if (*c=='b' || *c=='B')
  308.         { *c=' '; st->b = get_UBYTE(); if (valid_num) flag=1; }
  309.         else if (!flag) {
  310.             if (i==0)        st->r = get_UBYTE();
  311.             else if (i==1)    st->g = get_UBYTE();
  312.             else            st->b = get_UBYTE();
  313.             if (valid_num) cnt++;
  314.         }
  315.     }
  316.     if (!flag && cnt==1) {     /* Copy value into other two elements */
  317.         st->g = st->b = st->r;
  318.     }
  319. }
  320.  
  321. /********************/
  322. /* The MAIN section */
  323. /********************/
  324.  
  325. WORLD *read_TTDDD(file)
  326. FILE *file;
  327. {
  328.     char name[5];
  329.     WORLD *world;
  330.  
  331.     if (!file) return(0L); /* File not open */
  332.  
  333.     if (!(world = (WORLD*)malloc(sizeof(WORLD)))) { OUT_MEM("WORLD"); }
  334.     bzero((char*)world, sizeof(WORLD));
  335.     world->inp = file;
  336.  
  337.     if (already_read_header)    /* Copy the data into the "strin" */
  338.         strncpy(strin, header_storage, already_read_header);
  339.  
  340. /* Here is the main loop: */
  341.     while (get_line(strin, world)) {
  342.         parse_word(name, 4, 1);        /* And chop it out of the string */
  343.  
  344.         if        (strcmp(name, "INFO")==0) process_INFO(world);
  345.         else if (strcmp(name, "OBJ") ==0) process_OBJ(world);
  346.         else if (strcmp(name, "ISTG")==0) process_ISTG(world);
  347.         else {
  348.             fprintf(stderr, "Invalid chunk on line %d: '%s' (skipped)\n",
  349.                 world->cur_line, name);
  350.             continue;
  351.         }
  352.     }
  353.  
  354. /* All done.  Close up shop. */
  355.     return(world);
  356. }
  357.  
  358. static void process_INFO(world)
  359. WORLD *world;
  360. {
  361.     register INFO *info;
  362.     register ULONG i;
  363.     char this_level[MAXLINE], name[5];
  364.  
  365.     if (world->info) {
  366.         fprintf(stderr, "Parse error: More than one INFO chunk!\n"); exit(-1); }
  367.     if (!(info = world->info = (INFO*)malloc(sizeof(INFO)))) { OUT_MEM("INFO"); }
  368.     bzero((char *)world->info, sizeof(INFO));
  369.  
  370.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  371.     if (strcmp(this_level, "BEGIN") != 0) {
  372.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'INFO'\n",
  373.             world->cur_line);
  374.     }
  375.     parse_word(this_level, 0, 0);    /* No limit, original case */
  376.  
  377.     while (get_line(strin, world)) {
  378.         parse_word(name, 4, 1);        /* Get command */
  379.         if (strcmp(name, "BRSH")==0) {
  380.             i = get_UWORD();
  381.             if (i<0 || i>7) fputs("BRSH error.\n", stderr);
  382.             parse_word(ps, 0, 0);
  383.             strncpy(info->brsh[i], ps, 80);
  384.             info->brsh[i][80]='\0';
  385.         } else
  386.         if (strcmp(name, "STNC")==0) {
  387.             i = get_UWORD();
  388.             if (i<0 || i>7) fputs("STNC error.\n", stderr);
  389.             parse_word(ps, 0, 0);
  390.             strncpy(info->stnc[i], ps, 80);
  391.             info->stnc[i][80]='\0';
  392.         } else
  393.         if (strcmp(name, "TXTR")==0) {
  394.             i = get_UWORD();
  395.             if (i<0 || i>7) fputs("TXTR error.\n", stderr);
  396.             parse_word(ps, 0, 0);
  397.             strncpy(info->txtr[i], ps, 80);
  398.             info->txtr[i][80]='\0';
  399.         } else
  400.         if (strcmp(name, "OBSV")==0) {
  401.             if (!info->obsv) info->obsv=(OBSV*)malloc(sizeof(OBSV));
  402.             if (!info->obsv) { OUT_MEM("OBSV"); }
  403.             parse_word(name, 4, 1);        /* Get field */
  404.             if        (strcmp(name, "CAME")==0) stuff_XYZ(&info->obsv->came);
  405.             else if (strcmp(name, "ROTA")==0) stuff_XYZ(&info->obsv->rota);
  406.             else if (strcmp(name, "FOCA")==0) info->obsv->foca = get_FRACT();
  407.             else {
  408.                 if (verbose_flag)
  409.                     fprintf(stderr, "WARNING: Line %d: Unknown OBSV field: '%s'\n",
  410.                         world->cur_line, name);
  411.                 continue;
  412.             }
  413.         } else
  414.         if (strcmp(name, "OTRK")==0) {
  415.             parse_word(ps, 0, 0);
  416.             strncpy(info->otrk, ps, 18);
  417.             info->otrk[18]='\0';
  418.         } else
  419.         if (strcmp(name, "OSTR")==0) {
  420.             if (!info->ostr) info->ostr=(STRY*)malloc(sizeof(STRY));
  421.             if (!info->ostr) { OUT_MEM("OSTR"); }
  422.             parse_word(name, 4, 1);        /* Get field */
  423.             if (strcmp(name, "PATH")==0) parse_word(info->ostr->path, 18, 0);
  424.             else if (strcmp(name, "TRAN")==0) stuff_XYZ(&info->ostr->tran);
  425.             else if (strcmp(name, "ROTA")==0) stuff_XYZ(&info->ostr->rota);
  426.             else if (strcmp(name, "SCAL")==0) stuff_XYZ(&info->ostr->scal);
  427.             else
  428.             if (strcmp(name, "INFO")==0) {
  429.                 info->ostr->info = 0;
  430.                 while (strin[0]) {
  431.                     parse_word(ps, 7, 1);
  432.                     if        (strcmp(ps, "ABS_TRA")==0) info->ostr->info|=(1<<0);
  433.                     else if (strcmp(ps, "ABS_ROT")==0) info->ostr->info|=(1<<1);
  434.                     else if (strcmp(ps, "ABS_SCL")==0) info->ostr->info|=(1<<2);
  435.                     else if (strcmp(ps, "LOC_TRA")==0) info->ostr->info|=(1<<4);
  436.                     else if (strcmp(ps, "LOC_ROT")==0) info->ostr->info|=(1<<5);
  437.                     else if (strcmp(ps, "LOC_SCL")==0) info->ostr->info|=(1<<6);
  438.                     else if (strcmp(ps, "X_ALIGN")==0) info->ostr->info|=(1<<8);
  439.                     else if (strcmp(ps, "Y_ALIGN")==0) info->ostr->info|=(1<<9);
  440.                     else if (strcmp(ps, "Z_ALIGN")==0) info->ostr->info|=(1<<10);
  441.                     else if (strcmp(ps, "FOLLOW_")==0) info->ostr->info|=(1<<12);
  442.                     else {
  443.                         if (verbose_flag)
  444.                             fprintf(stderr, "WARNING: Line %d: Unknown OSTR INFO flag: '%s'\n",
  445.                                 world->cur_line, ps);
  446.                         continue;
  447.                     }
  448.                 }
  449.             } else {
  450.                 if (verbose_flag)
  451.                     fprintf(stderr, "WARNING: Line %d: Unknown OSTR field: '%s'\n",
  452.                         world->cur_line, name);
  453.                 continue;
  454.             }
  455.         } else
  456.         if (strcmp(name, "FADE")==0) {
  457.             if (!info->fade) info->fade=(FADE*)malloc(sizeof(FADE));
  458.             if (!info->fade) { OUT_MEM("FADE"); }
  459.             parse_word(ps, 6, 1);        /* Get field */
  460.             if        (strcmp(ps, "FADEAT")==0) info->fade->at = get_FRACT();
  461.             else if (strcmp(ps, "FADEBY")==0) info->fade->by = get_FRACT();
  462.             else if (strcmp(ps, "FADETO")==0) stuff_RGB(&info->fade->to);
  463.             else {
  464.                 if (verbose_flag)
  465.                     fprintf(stderr, "WARNING: Line %d: Unknown FADE field: '%s'\n",
  466.                         world->cur_line, ps);
  467.                 continue;
  468.             }
  469.         } else
  470.         if (strcmp(name, "SKYC")==0) {
  471.             if (!info->skyc) info->skyc=(SKYC*)malloc(sizeof(SKYC));
  472.             if (!info->skyc) { OUT_MEM("SKYC"); }
  473.             parse_word(name, 4, 1);        /* Get field */
  474.             if        (strcmp(name, "HORI")==0) stuff_RGB(&info->skyc->hori);
  475.             else if (strcmp(name, "ZENI")==0) stuff_RGB(&info->skyc->zeni);
  476.             else {
  477.                 if (verbose_flag)
  478.                     fprintf(stderr, "WARNING: Line %d: Unknown SKYC field: '%s'\n",
  479.                         world->cur_line, name);
  480.                 continue;
  481.             }
  482.         } else
  483.         if (strcmp(name, "AMBI")==0) {
  484.             if (!info->ambi) info->ambi=(RGB_st*)malloc(sizeof(RGB_st));
  485.             if (!info->ambi) { OUT_MEM("AMBI"); }
  486.             stuff_RGB(info->ambi);
  487.         } else
  488.         if (strcmp(name, "GLB0")==0) {
  489.             if (!info->glb0) info->glb0=(BYTE*)malloc(8*sizeof(BYTE));
  490.             if (!info->glb0) { OUT_MEM("GLB0"); }
  491.             i = get_ULONG();    /* Index into array */
  492.             if (i>=0 && i<8) {
  493.                 info->glb0[i] = (BYTE) get_ULONG();
  494.             } else
  495.                 fprintf(stderr, "WARNING: Line %d: Bad index: GLB0[%d] should be [0..7]\n", world->cur_line, i);
  496.         } else if (strcmp(name, "END")==0) {
  497.             parse_word(name, 4, 1);
  498.             if (strcmp(name, "INFO")!=0)
  499.                 fprintf(stderr, "WARNING: Line %d: Expected 'END INFO' but got: 'END %s'\n", world->cur_line, name);
  500.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  501.             if (strcmp(this_level, ps)!=0)
  502.                 fprintf(stderr, "WARNING: Line %d: 'INFO Begin' and 'End INFO' quoted comments do not match\n", world->cur_line);
  503.             break;
  504.         } else if (verbose_flag)
  505.             fprintf(stderr, "WARNING: Line %d: Unknown INFO sub-sub-chunk: '%s'\n",
  506.                 world->cur_line, name);
  507.     }
  508. }
  509.  
  510. OBJECT *create_object()
  511. {
  512.     OBJECT *p;
  513.     p = (OBJECT*)malloc(sizeof(OBJECT));
  514.     if (!p) { OUT_MEM("Create"); }
  515.     bzero((char*)p,sizeof(OBJECT));
  516.     return(p);
  517. }
  518.  
  519. static void process_OBJ(world)
  520. WORLD *world;
  521. {
  522.     char this_level[MAXLINE], name[5];
  523.     register OBJECT *p;
  524.     int depth;
  525.  
  526.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  527.     if (strcmp(this_level, "BEGIN") != 0) {
  528.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'OBJ'\n",
  529.             world->cur_line);
  530.     }
  531.     parse_word(this_level, 0, 0);    /* No limit, original case */
  532.  
  533.     depth=0;
  534.     while (get_line(strin, world)) {
  535.         parse_word(name, 4, 1);        /* Get command */
  536.         if        (strcmp(name, "EXTR")==0) {
  537.             p = process_EXTR(create_object(), world);
  538.             if (world->curobj) {
  539.                 world->curobj->next = p;
  540.                 p->parent = world->curobj->parent;
  541.             } else {
  542.                 world->object = p;
  543.                 p->parent = 0;
  544.             }
  545.             world->curobj = p;
  546.         
  547. /*
  548.  
  549. Glenn:
  550.     Here is the merging code.  I also tried loading grouped objects into
  551. the detail editor, with similar results to what I was seeing when I was loading
  552. massive numbers of separate objects.  Results are below, but I think this will
  553. complicate our lives considerably.
  554.     Cheers,
  555.     Charles
  556.  
  557. ------------------------------------------------------------------------------
  558. Charles Congdon                                      Oracle Corporation
  559. Special Projects                                     2580 SW 192nd Ave.
  560. Midrange Systems Group, DEC Products Division        Aloha, OR   97006
  561. Office:  (415) 506-6341                              FAX:  (415) 506-6341
  562. Internet:  ccongdon@us.oracle.com               Usenet:  uunet!oracle!ccongdon
  563. ------------------------------------------------------------------------------
  564.  
  565.              MODIFICATIONS TO READ.C TO SUPPORT MXTR CHUNKS
  566.          ==============================================
  567.  
  568. Purpose:
  569.  
  570.     These routines allow the following construct:
  571.     
  572.     MXTR Begin
  573.     
  574.     EXTR Begin
  575.     <etc>
  576.     End EXTR
  577.     
  578.     EXTR Begin
  579.     <etc>
  580.     End EXTR
  581.     
  582.     EXTR Begin
  583.     <etc>
  584.     End EXTR
  585.     :
  586.     :
  587.     :
  588.     
  589.     End MXTR
  590.  
  591. Everything within the MXTR chunk is merged into one huge object.  Over
  592. 750 objects have been merged with this code, resulting in objects with
  593. point, face, and edge counts in the mid-thousands (oh yes, and over
  594. 1400 subgroups!).  I really mean "merge" here, not group. 
  595.  
  596. The last EXTR object in the list defines the face-insensitive
  597. attributes like hardness, specular, etc. for the entire mega object.
  598. NOTE:  this implies that if you are merging two EXTR objects, one with
  599. a zero hardness, and one with a hardness of 255, then which ever is
  600. the last in the list before End MXTR defines the hardness for all.  In
  601. short, don't merge objects with vastly differing face-insensitive
  602. attributes (for example, chrome and rubber).
  603.  
  604. All component EXTR objects contribute to fill in the face-sensitive
  605. attributes (point, edge, face, color, reflect, and filter information)
  606. for the object (i.e. - all face-specific attributes are preserved for
  607. all faces of all component EXTR objects).  Yes, that includes all
  608. subgroups defined for all component EXTR objects.  Names of subgroups
  609. will be "mangled" with a counter to better let you identify who to
  610. change.  I considered merging subgroups (since they can build up
  611. fast), but figured that is best for a future enhancement. 
  612.  
  613. Face-sensitive "attributes" that were thrown out entirely are textures
  614. and brushmaps.  The reason is that these are limited to 4 per object.
  615. What do you do when you merge 1000 objects, each with three textures
  616. defined?  Which 4 textures do you use?  What should the texture axis
  617. positions be?  How about the texture scale factors?  In short, apply
  618. your textures to your merged object (using subgroups if you wish to
  619. restrict the scope) once you have loaded it into Imagine. 
  620.  
  621. Another limitation is that at present I do not support heirachical
  622. EXTR objects.  If you look at the length of the code below, I think
  623. you will understand why.  To do so, simply unroll the heirarchy into
  624. the master object.  This will require an additional preprocessing step
  625. to properly calculate point, edge, and face counts, and some recursion
  626. in the main copying loop.  NOTE:  By not preserve I mean two things:
  627. 1) at present I only copy the parent of an EXTR object that is
  628. actually a group.  2) I don't try to build heirarchy into the merged
  629. object either. 
  630.  
  631. Why not *preserve* heirachies, you ask?  Because Imagine reacts poorly
  632. to the creation of massive numbers of objects at a time.  Loading any
  633. more than 100-300 objects at a time into the detail results in a wait
  634. that can stretch on for hours as Imagine sets up for fast access to
  635. these objects.  The objects all happily draw in the tri-view window
  636. almost instantly, but the pointer remains BUSY for a *long* time.
  637. Once the BUSY pointer vanishes, Imagine draws the wireframe appears in
  638. the perspective window.   From that point on, access to all objects in
  639. the detail editor acts normally.
  640.  
  641. For example, adding 128 grouped objects in the detail editor (by a
  642. simple paste operation from a copy of an existing set of 128 grouped
  643. objects) resulted in a wait of over 5 minutes on a vanilla A3000 with
  644. 14M.  Over 11M remained free.  Loading 256 objects resulted in a wait
  645. of 15 minutes (over 9 M remained free).  These were 4 point, 6 edge, 2
  646. face objects.  The wait seems to go up as a high power of object
  647. complexity.  Loading 243 objects only twice as complex took longer
  648. than 1/2 - 3/4 hours, at which time I gave up and rebooted.   Nothing
  649. else was happening on the machine at the time.
  650.  
  651. Also, I wrote this code to allow the merging of massive numbers of
  652. *simple*, nearly identical objects.  You know, so I can merge blades
  653. of grass to make a lawn.  Or many individual leaves to make a leafy
  654. tree.  In this case, the above limitation clamps down on one fast.  If
  655. you want to merge only 40 EXTR objects, with a group of a parent and
  656. two children objects each - fine, write a GXTR chunk to handle this -
  657. 120 objects is managable, barely.  But any more than this and you
  658. should reconsider what you are trying to do. 
  659.  
  660. Hence, no groups of objects when merging (although you are free to
  661. change this - just don't break the existing functionality of MXTR)
  662.  
  663. 2)  An addition to process_OBJ(world):
  664.  
  665. */
  666.  
  667.                 /*--------------------------------------------\        
  668.                 |  Charles' magical EXTR object merge hack.   |
  669.                 \--------------------------------------------*/
  670.         } else if (strcmp(name, "MXTR")==0) {
  671.             p = process_MXTR(create_object(), world);
  672.             if (world->curobj) {
  673.                 world->curobj->next = p;
  674.                 p->parent = world->curobj->parent;
  675.             } else {
  676.                 world->object = p;
  677.                 p->parent = 0;
  678.             }
  679.             world->curobj = p;
  680.  
  681.                 /*---------------------------------------------------\        
  682.                 |  End of Charles' magical EXTR object merge hack.   |
  683.                 \---------------------------------------------------*/
  684.  
  685.         } else if (strcmp(name, "DESC")==0) {
  686.             p = create_object();
  687.             if (world->num_DESC > world->num_TOBJ+depth) {    /* This is a child */
  688.                 depth++;    /* Down one in the hierarchy */
  689.                 world->curobj->child = p;
  690.                 p->parent = world->curobj;
  691.             } else {
  692.                 if (world->curobj) {
  693.                     world->curobj->next = p;
  694.                     p->parent = world->curobj->parent;
  695.                 } else {
  696.                     world->object = p;
  697.                     p->parent = 0;
  698.                 }
  699.             }
  700.             world->curobj = p;
  701.             process_DESC(&p->desc, world);
  702.         } else if (strcmp(name, "TOBJ")==0) {
  703.             world->num_TOBJ++;
  704.             if (world->num_TOBJ > world->num_DESC) {
  705.                 warn(world->cur_line);
  706.                 fprintf(stderr, "TOBJ without DESC.  Ignored.\n");
  707.             }
  708.             if (world->num_TOBJ+depth > world->num_DESC) {    /* Go back up a level */
  709.                 depth--;
  710.                 world->curobj=world->curobj->parent;
  711.             }
  712.         } else if (strcmp(name, "END" )==0) {
  713.             if (world->num_DESC > world->num_TOBJ) {
  714.                 int i;
  715.                 warn(world->cur_line);
  716.                 i = world->num_DESC - world->num_TOBJ;
  717.                 fprintf(stderr, "Missing %d 'TOBJ'.  Inserted.\n", i);
  718.             }
  719.             parse_word(name, 4, 1);
  720.             if (strcmp(name, "OBJ")!=0)
  721.                 fprintf(stderr, "WARNING: Line %d: Expected 'END OBJ' but got: 'END %s'\n", world->cur_line, name);
  722.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  723.             if (strcmp(this_level, ps)!=0)
  724.                 fprintf(stderr, "WARNING: Line %d: 'OBJ Begin' and 'End OBJ' quoted comments do not match\n", world->cur_line);
  725.             break;
  726.         } else if (verbose_flag)
  727.             fprintf(stderr, "WARNING: Line %d: Unknown OBJ sub-sub-chunk: '%s'\n",
  728.                 world->cur_line, name);
  729.     }
  730. }
  731.  
  732. /*---------------------------------------------------------\
  733. |  How to merge EXTR objects into a single mega object.    |
  734. \---------------------------------------------------------*/
  735. static OBJECT *process_MXTR(obj, world)
  736. OBJECT *obj;
  737. WORLD  *world;
  738. {    /* process_MXTR */
  739.         register OBJECT   *p, *base, *end;
  740.         register DESC     *desc, *edesc;
  741.         char              this_level[MAXLINE], name[5], nummy[8];
  742.         ULONG             pcount, ecount, fcount;
  743.         ULONG             pstart, estart, fstart;
  744.         ULONG             i;
  745.         XYZ_st            *crd, *ocrd;
  746.         ULONG             fcnt, ecnt, extrcount;
  747.         FGRP              *fgrp, *ofgrp;
  748.  
  749.         pcount = ecount = fcount = 0;
  750.         
  751.         /*---------------------------------------------------------------------\
  752.         |  Set up place-holder object - we store all EXTR objects in a linked  |
  753.         |  list, then merge into obj once we hit END MXTR.                     |
  754.         \---------------------------------------------------------------------*/
  755.         base = create_object();
  756.  
  757.         base->parent = (struct OBJECT *)0;
  758.         end = base;
  759.  
  760.         parse_word(this_level, 0, 1);   /* No limit, uppercase. */
  761.         if (strcmp(this_level, "BEGIN") != 0) {
  762.                 fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'MXTR'\n",
  763.                         world->cur_line);
  764.         }
  765.         parse_word(this_level, 0, 0);   /* No limit, original case */
  766.         
  767.         /*---------------------------------------------------------------\      
  768.         |  Get EXTR objects to merge until END MXTR.  Any other chuck    |
  769.         |  ignored.                                                      |
  770.         \---------------------------------------------------------------*/
  771.  
  772.         while (get_line(strin, world)) {
  773.                 parse_word(name, 4, 1);         /* Get command */
  774.                 if   (strcmp(name, "EXTR")==0) {
  775.                    /*-----------------------------------------------------\             
  776.                    |  Read all EXTR objects that make up this "group".    |
  777.                    \-----------------------------------------------------*/
  778.                    p = process_EXTR(create_object(), world);
  779.                    pcount = pcount + p->desc->pcount;
  780.                    ecount = ecount + p->desc->ecount;
  781.                    fcount = fcount + p->desc->fcount;
  782.                    end->next = p;
  783.                    p->parent = end;
  784.                    end = p;
  785.                 } else if (strcmp(name, "END" )==0) {
  786.                   /*-------------------------------------\              
  787.                   |  End off this EXTR object series.    |
  788.                   \-------------------------------------*/
  789.                   parse_word(name, 4, 1);  
  790.                   if (strcmp(name, "MXTR")!=0)
  791.                      fprintf(stderr, "WARNING: Line %d: Expected 'END MXTR' but got: 'END %s'\n", world->cur_line, name);
  792.                   parse_word(ps, 0, 0); /* Get the quote, if any */
  793.                   if (strcmp(this_level, ps)!=0)
  794.                         fprintf(stderr, "WARNING: Line %d: 'MXTR Begin' and 'End MXTR' quoted comments do not match\n", world->cur_line);
  795.                   break;
  796.                 }
  797.         }   /* while MXTR */
  798.  
  799.  
  800.          /*-------------------------------------------------\   
  801.          |  OK, cap base object for our collection scan.    |
  802.          \-------------------------------------------------*/
  803.          end->next = (struct OBJECT *)0;
  804.  
  805.          end = base->next;   /* Return to first object */
  806.          base->next = (struct OBJECT *)0;  /* Since when it comes time to
  807.                                        free, this is all that will be left */
  808.          edesc = end->desc;
  809.          
  810.          /*----------------------------\
  811.          |  Set up our mega object.    |
  812.          \----------------------------*/
  813.          if (!(desc = (DESC*)malloc(sizeof(DESC)))) { OUT_MEM("DESC"); }
  814.          bzero((char*)desc, sizeof(DESC));
  815.          obj->desc = desc;
  816.  
  817.          /*-------------------------------------------------------\
  818.          |  Copy all attributes from 1st object in EXTR chain.    |
  819.          \-------------------------------------------------------*/
  820.          desc_copy(edesc, desc);        
  821.  
  822.          
  823.          /*------------------------\     
  824.          |  Set a few defaults.    |
  825.          \------------------------*/
  826.  
  827.          /* Set up defaults: */
  828.          defclst[0] = defclst[1] = defclst[2] = 240;    /* TS default */
  829.          defrlst[0] = defrlst[1] = defrlst[2] = 0;
  830.          deftlst[0] = deftlst[1] = deftlst[2] = 0;
  831.          defspc1[0] = defspc1[1] = defspc1[2] = 0;
  832.  
  833.          desc->pcount = pcount;
  834.          desc->ecount = ecount;
  835.  
  836.          /*----------------------------------------------------\
  837.          |  Allocate space for point, face, and edge arrays.   |
  838.          \----------------------------------------------------*/
  839.          if (!(desc->pnts = (XYZ_st*)malloc(desc->pcount*sizeof(XYZ_st))))
  840.                                 OUT_MEM("PNTS");
  841.          /* Initialize array */
  842.          for (i=0; i<desc->pcount; i++) {
  843.              desc->pnts[i].x = 0;
  844.              desc->pnts[i].y = 0;
  845.              desc->pnts[i].z = 0;
  846.          }
  847.  
  848.          if (!(desc->edge = (UWORD*)malloc(2*desc->ecount*sizeof(UWORD))))
  849.                                 OUT_MEM("EDGE");
  850.          /* Initialize array */
  851.          for (i=0; i<2*desc->ecount; i++)
  852.              desc->edge[i] = 0;
  853.  
  854.          malloc_arrays(fcount, desc);
  855.  
  856.          /*---------------------------------------------------------\
  857.          |  Now walk down objects, copying point, face, edge,       |
  858.          |  color, transparancy, and reflectivity information.      |
  859.          |  All other attributes have been stolen from the first    |
  860.          |  object.  Subobjects are copied                          |
  861.          |  POTENTIAL BUG:  I AM ASSUMING THE EXTR OBJECTS WE READ  |
  862.          |  HERE ARE NOT THEMSELVES HIERACHIES.   MIGHT NEED SOME   |
  863.          |  RECURSION, OR SOMETHING SIMILAR, IF THIS IS THE CASE.   |
  864.          \---------------------------------------------------------*/
  865.          ocrd = desc->pnts;
  866.          
  867.          pstart = estart = fstart = 0;
  868.          fcnt = ecnt = extrcount = 0;
  869.  
  870.          while (end != (struct OBJECT *)0)
  871.          {     /* For all objects to merge */
  872.             edesc = end->desc;
  873.             /*---------------------------------------------------------------\    
  874.             |  Copy points over - OK, I could use BCOPY, but I want control. |
  875.             \---------------------------------------------------------------*/
  876.             crd = edesc->pnts;
  877.             for (i = 0; i < edesc->pcount; i++)
  878.             {
  879.                ocrd->x = crd->x;
  880.                ocrd->y = crd->y;
  881.                ocrd->z = crd->z;
  882.                ocrd++;
  883.                crd++;
  884.             }
  885.             
  886.             /*---------------\      
  887.             |  Now edges.    |
  888.             \---------------*/
  889.             
  890.             for (i=0; i<2*edesc->ecount; i++)
  891.             {
  892.                desc->edge[ecnt] = edesc->edge[i] + pstart;
  893.                ecnt++;
  894.             }
  895.                
  896.             /*----------------------------------------------\       
  897.             |  And the faces and their basic attributes.    |
  898.             \----------------------------------------------*/
  899.             for (i = 0; i<3*edesc->fcount; i+=3)
  900.             {
  901.                desc->face[fcnt]   = edesc->face[i] + estart;
  902.                desc->face[fcnt+1] = edesc->face[i+1] + estart;
  903.                desc->face[fcnt+2] = edesc->face[i+2] + estart;
  904.                desc->clst[fcnt]   = edesc->clst[i];
  905.                desc->clst[fcnt+1] = edesc->clst[i+1];
  906.                desc->clst[fcnt+2] = edesc->clst[i+2];
  907.                desc->rlst[fcnt]   = edesc->rlst[i];
  908.                desc->rlst[fcnt+1] = edesc->rlst[i+1];
  909.                desc->rlst[fcnt+2] = edesc->rlst[i+2];
  910.                desc->tlst[fcnt]   = edesc->tlst[i];
  911.                desc->tlst[fcnt+1] = edesc->tlst[i+1];
  912.                desc->tlst[fcnt+2] = edesc->tlst[i+2];
  913.                fcnt+=3;
  914.             }
  915.             
  916.             /*----------------------------------\           
  917.             |  And the subgroup definitions.    |
  918.             \----------------------------------*/
  919.             if (edesc->fgrp)
  920.             {       /* Do subgroups */
  921.                fgrp = edesc->fgrp;
  922.                while (fgrp != (FGRP *) 0)
  923.                {    /* While subgroups to copy */
  924.                   /*------------------------\       
  925.                   |  Get FGRP structure.    |
  926.                   \------------------------*/
  927.                   if (!(ofgrp = (FGRP*)malloc(sizeof(FGRP))))
  928.                                OUT_MEM("FGRP");
  929.                   /*------------------------------\
  930.                   |  Fill out name and number.    |
  931.                   \------------------------------*/
  932.                   bzero((char *)ofgrp, sizeof(FGRP));
  933.                   
  934.                   ofgrp->num = fgrp->num;
  935.                   
  936.                   /*-----------------------------------------------\              
  937.                   |  Mangle name so unique for each subobject of   |
  938.                   |  each component EXTR object.                   |
  939.                   \-----------------------------------------------*/
  940.                   i = strlen(fgrp->name);
  941.                   if (i > 13)   /* The name field is 18 characters  */
  942.                      i = 13;    /* tops, and we remove 5 characters for
  943.                                        the ASCII representations of 0-65535 */
  944.                   strncpy(ofgrp->name, fgrp->name, i);
  945.                   ofgrp->name[i] = '\0';   /* Arrays start at 0 */
  946.                   sprintf(nummy, "%d", extrcount);
  947.                   strcat(ofgrp->name, nummy);   /* uniquely tag subgroup
  948.                                                    name by number of parent
  949.                                                    EXTR object */
  950.                   
  951.                   /*-----------------------------\                
  952.                   |  Insert into linked list.    |
  953.                   \-----------------------------*/
  954.                   ofgrp->next = desc->fgrp;
  955.                   desc->fgrp = ofgrp;
  956.                      
  957.                   /*-----------------------------------\                  
  958.                   |  And copy in the face indicies.    |
  959.                   \-----------------------------------*/
  960.                   if (!(ofgrp->face = 
  961.                            (UWORD *)malloc((fgrp->num)*sizeof(UWORD))))
  962.                                         OUT_MEM("FGRP");
  963.                   for (i = 0; i < fgrp->num; i++)
  964.                   {
  965.                      ofgrp->face[i] = (UWORD) (fgrp->face[i] + fstart);
  966.                   }
  967.                   
  968.                   fgrp = fgrp->next;
  969.                }    /* While subgroups to copy */
  970.             }       /* Do subgroups */
  971.  
  972.             /*-------------------------------------------------------\      
  973.             |  Copying textures in a similar manner would be         |
  974.             |  rather difficult, since we can only have 4 textures   |
  975.             |  per object.  I suggest having the user make their     |
  976.             |  own subgroups and apply the texture to the merged     |
  977.             |  object, since we run into too many difficulties if    |
  978.             |  we try to do this for them here.  There is a time     |
  979.             |  and a place for everything, and I think textures      |
  980.             |  don't belong here.                                    |
  981.             \-------------------------------------------------------*/
  982.  
  983.             /*----------------------------\         
  984.             |  Set up for next object.    |
  985.             \----------------------------*/
  986.             pstart = pstart + edesc->pcount;
  987.             estart = estart + edesc->ecount;
  988.             fstart = fstart + edesc->fcount;
  989.             extrcount++;
  990.             p = end;
  991.             end = end->next;
  992.  
  993.             /*--------------------------------------------------\           
  994.             |  And free object now that we are done with it.    |
  995.             \--------------------------------------------------*/
  996.             p->next = (struct OBJECT *)0;   /* Delete only this guy in chain */
  997.             p->parent = (struct OBJECT *)0;
  998.             free_object(p);
  999.          }       /* For all objects to merge */
  1000.  
  1001.          /*---------------------\
  1002.          |  Free base object.   |
  1003.          \---------------------*/
  1004.          free_object(base);
  1005.          
  1006.          /*-------------------------\    
  1007.          |  And return in glory.    |
  1008.          \-------------------------*/
  1009.          return(obj);
  1010.  
  1011. }    /* process_MXTR */
  1012.  
  1013. /*-------------------------------------------------------------------\
  1014. |  Copy an object's attributes from one desc structure to another.   |
  1015. |  What a pain.  But someone had to do it...                         |
  1016. \-------------------------------------------------------------------*/
  1017. static void desc_copy(edesc, desc)
  1018. DESC *edesc, /* input desc structure */
  1019.      *desc;  /* output desc structure */
  1020. {     /* desc_copy */
  1021.    if (edesc->name != '\0')
  1022.       strcpy(desc->name, edesc->name);
  1023.  
  1024.    if (edesc->eflg)
  1025.    {
  1026.       if (!(desc->eflg = (EFLG*)malloc(sizeof(EFLG))))
  1027.                         OUT_MEM("EFLG");
  1028.       bcopy((char *)edesc->eflg, (char *)desc->eflg, sizeof(EFLG));
  1029.       if (edesc->eflg->eflg)
  1030.       {
  1031.          if (!(desc->eflg->eflg = 
  1032.               (UBYTE*)malloc(desc->eflg->num*sizeof(UBYTE))))
  1033.                     OUT_MEM("EFLG");
  1034.          bcopy((char *)edesc->eflg->eflg, (char *)edesc->eflg->eflg, 
  1035.                edesc->eflg->num*sizeof(UBYTE));
  1036.       }
  1037.    }
  1038.                  
  1039.    if (edesc->shap)
  1040.    {
  1041.       if (!(desc->shap=(WORD*)malloc(2*sizeof(WORD))))
  1042.                                         { OUT_MEM("SHAP"); }
  1043.       bcopy((char *)edesc->shap, (char *)desc->shap, 2*sizeof(WORD));
  1044.    }
  1045.          
  1046.    if (edesc->posi)
  1047.    {
  1048.       if (!(desc->posi=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1049.                                         { OUT_MEM("POSI"); }
  1050.       bcopy((char *)edesc->posi, (char *)desc->posi, sizeof(XYZ_st));
  1051.    }
  1052.  
  1053.    if (edesc->axis)
  1054.    {
  1055.       if (!(desc->axis=(AXIS*)malloc(sizeof(AXIS))))
  1056.                 { OUT_MEM("AXIS"); }
  1057.       bcopy((char *)edesc->axis, (char *)desc->axis, sizeof(AXIS));
  1058.    }
  1059.    
  1060.    if (edesc->size)
  1061.    {
  1062.       if (!(desc->size=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1063.                         { OUT_MEM("SIZE"); }
  1064.       bcopy((char *)edesc->size, (char *)desc->size, sizeof(XYZ_st));
  1065.    }
  1066.  
  1067.    if (edesc->colr)
  1068.    {
  1069.       if (!(desc->colr = (RGB_st*)malloc(sizeof(RGB_st))))
  1070.                                         { OUT_MEM("COLR"); }
  1071.       bcopy((char *)edesc->colr, (char *)desc->colr, sizeof(RGB_st));
  1072.    }
  1073.    
  1074.    if (edesc->refl)
  1075.    {
  1076.       if (!(desc->refl = (RGB_st*)malloc(sizeof(RGB_st))))
  1077.                                         { OUT_MEM("REFL"); }
  1078.       bcopy((char *)edesc->refl, (char *)desc->refl, sizeof(RGB_st));
  1079.    }
  1080.  
  1081.    if (edesc->tran)
  1082.    {
  1083.       if (!(desc->tran = (RGB_st*)malloc(sizeof(RGB_st))))
  1084.                                         { OUT_MEM("TRAN"); }
  1085.       bcopy((char *)edesc->tran, (char *)desc->tran, sizeof(RGB_st));
  1086.    }
  1087.  
  1088.    if (edesc->spc1)
  1089.    {
  1090.       if (!(desc->spc1 = (RGB_st*)malloc(sizeof(RGB_st))))
  1091.                                         { OUT_MEM("SPC1"); }
  1092.       bcopy((char *)edesc->spc1, (char *)desc->spc1, sizeof(RGB_st));
  1093.    }
  1094.  
  1095.    if (edesc->tpar)
  1096.    {
  1097.       if (!(desc->tpar=(double*)malloc(16*sizeof(double))))
  1098.                                         { OUT_MEM("TPAR"); }
  1099.       bcopy((char *)edesc->tpar, (char *)desc->tpar, 16*sizeof(double));
  1100.    }
  1101.  
  1102.    if (edesc->surf)
  1103.    {
  1104.       if (!(desc->surf=(UBYTE*)malloc(5*sizeof(UBYTE))))
  1105.                                         { OUT_MEM("SURF"); }
  1106.       bcopy((char*)edesc->surf, (char *)desc->surf, 5*sizeof(UBYTE));
  1107.    }
  1108.  
  1109.    if (edesc->mttr)
  1110.    {
  1111.       if (!(desc->mttr=(MTTR*)malloc(sizeof(MTTR))))
  1112.                                         { OUT_MEM("MTTR"); }
  1113.       bcopy((char*)edesc->mttr, (char *)desc->mttr, sizeof(MTTR));
  1114.    }
  1115.    
  1116.    if (edesc->spec)
  1117.    {
  1118.       if (!(desc->spec=(UBYTE*)malloc(2*sizeof(UBYTE))))
  1119.                                         { OUT_MEM("SPEC"); }
  1120.       bcopy((char*)edesc->spec, (char *)desc->spec, 2*sizeof(UBYTE));
  1121.    }
  1122.  
  1123.    if (edesc->prp0)
  1124.    {
  1125.       if (!(desc->prp0=(UBYTE*)malloc(6*sizeof(UBYTE))))
  1126.                                         { OUT_MEM("PRP0"); }
  1127.       bcopy((char*)edesc->prp0, (char *)desc->prp0, 6*sizeof(UBYTE));
  1128.    }
  1129.  
  1130.    if (edesc->prp1)
  1131.    {
  1132.       if (!(desc->prp1=(UBYTE*)malloc(8*sizeof(UBYTE))))
  1133.                                         { OUT_MEM("PRP1"); }
  1134.       bcopy((char*)edesc->prp1, (char *)desc->prp1, 8*sizeof(UBYTE));
  1135.    }
  1136.  
  1137.    if (edesc->ints)
  1138.    {
  1139.       if (!(desc->ints=(double*)malloc(sizeof(double))))
  1140.                                         { OUT_MEM("INTS"); }
  1141.       bcopy((char *)edesc->ints, (char *)desc->ints, sizeof(double));
  1142.    }
  1143.    
  1144.    if (edesc->int1)
  1145.    {
  1146.       if (!(desc->int1=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1147.                                    { OUT_MEM("INT1"); }
  1148.       bcopy((char *)edesc->int1, (char *)desc->int1, sizeof(XYZ_st));
  1149.    }
  1150. }     /* desc_copy */
  1151. /*----------------------\
  1152. |  That's all folks.    |
  1153. \----------------------*/
  1154.  
  1155. static OBJECT *process_EXTR(obj, world)
  1156. OBJECT *obj;
  1157. WORLD *world;
  1158. {
  1159.     register EXTR *extr;
  1160.     register OBJECT *p;
  1161.     char this_level[MAXLINE], name[5];
  1162.     MTRX *mtrx;
  1163.     WORLD *new;
  1164.     FILE *newinp;
  1165.  
  1166.     if (!(extr = obj->extr = (EXTR*)malloc(sizeof(EXTR)))) { OUT_MEM("EXTR"); }
  1167.     bzero((char*)extr, sizeof(EXTR));
  1168.     mtrx = &extr->mtrx;
  1169.     /* Initialize structure */
  1170.     mtrx->tran.x  = mtrx->tran.y  = mtrx->tran.z  = 0.0;
  1171.     mtrx->scal.x  = mtrx->scal.y  = mtrx->scal.z  = 1.0;
  1172.     mtrx->rota1.y = mtrx->rota1.z = 0.0;
  1173.     mtrx->rota2.x = mtrx->rota2.z = 0.0;
  1174.     mtrx->rota3.x = mtrx->rota3.y = 0.0;
  1175.     mtrx->rota1.x = mtrx->rota2.y = mtrx->rota3.z = 1.0;
  1176.  
  1177.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  1178.     if (strcmp(this_level, "BEGIN") != 0) {
  1179.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'EXTR'\n",
  1180.             world->cur_line);
  1181.     }
  1182.     parse_word(this_level, 0, 0);    /* No limit, original case */
  1183.  
  1184.     while (get_line(strin, world)) {
  1185.         parse_word(name, 4, 1);        /* Get command */
  1186.         if        (strcmp(name, "MTRX")==0) {
  1187.             parse_word(name, 4, 1);        /* Get field */
  1188.             if      (strcmp(name, "TRAN")==0) stuff_XYZ(&mtrx->tran);
  1189.             else if (strcmp(name, "SCAL")==0) stuff_XYZ(&mtrx->scal);
  1190.             else if (strcmp(name, "ROTA")==0) {
  1191.                 stuff_XYZ(&mtrx->rota1);
  1192.                 stuff_XYZ(&mtrx->rota2);
  1193.                 stuff_XYZ(&mtrx->rota3);
  1194.             } else {
  1195.                 if (verbose_flag)
  1196.                     fprintf(stderr, "WARNING: Line %d: Unknown MTRX field: '%s'\n",
  1197.                         world->cur_line, name);
  1198.                 continue;
  1199.             }
  1200.         } else if (strcmp(name, "LOAD")==0) {
  1201.             parse_word(extr->filename, 80, 0);
  1202.         } else if (strcmp(name, "END" )==0) {
  1203.             parse_word(name, 4, 1);
  1204.             if (strcmp(name, "EXTR")!=0)
  1205.                 fprintf(stderr, "WARNING: Line %d: Expected 'END EXTR' but got: 'END %s'\n", world->cur_line, name);
  1206.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  1207.             if (strcmp(this_level, ps)!=0)
  1208.                 fprintf(stderr, "WARNING: Line %d: 'EXTR Begin' and 'End EXTR' quoted comments do not match\n", world->cur_line);
  1209.             break;
  1210.         } else if (verbose_flag)
  1211.             fprintf(stderr, "WARNING: Line %d: Unknown EXTR sub-sub-chunk: '%s'\n",
  1212.                 world->cur_line, name);
  1213.     }
  1214.     /* Now, load in the external object */
  1215.     if (!(newinp=fopen(extr->filename, "r"))) {
  1216.         fprintf(stderr, "Can't load in EXTR object: '%s'... ignored.\n",
  1217.             extr->filename);
  1218.         return(obj);
  1219.     }
  1220.     new = read_World(newinp);
  1221.     fclose(newinp);
  1222.     /* scale, rotate, and translate new object hierarchy */
  1223.     for (p=new->object; p; p=p->next)
  1224.         move_extr(p, mtrx);
  1225.     /* Free up unused memory */
  1226.     free((char*)obj->extr);
  1227.     free((char*)obj);
  1228.     obj = new->object;
  1229.     free((char*)new);
  1230.     return(obj);
  1231. }
  1232.  
  1233. void move_extr(obj, mtrx)
  1234. register OBJECT *obj;
  1235. register MTRX *mtrx;
  1236. {
  1237.     register XYZ_st *p;
  1238.     register int i;
  1239.     register double x, y, z;
  1240.     if (obj->desc) {
  1241.         if (obj->desc->posi) {
  1242.             obj->desc->posi->x += mtrx->tran.x;
  1243.             obj->desc->posi->y += mtrx->tran.y;
  1244.             obj->desc->posi->z += mtrx->tran.z;
  1245.         }
  1246.         for (p=obj->desc->pnts,i=obj->desc->pcount; i--; p++) {
  1247.             x = (p->x*mtrx->scal.x);
  1248.             y = (p->y*mtrx->scal.y);
  1249.             z = (p->z*mtrx->scal.z);
  1250.             p->x = x*mtrx->rota1.x +
  1251.                         y*mtrx->rota1.y +
  1252.                         z*mtrx->rota1.z +
  1253.                         mtrx->tran.x;
  1254.             p->y = x*mtrx->rota2.x +
  1255.                         y*mtrx->rota2.y +
  1256.                         z*mtrx->rota2.z +
  1257.                         mtrx->tran.y;
  1258.             p->z = x*mtrx->rota3.x +
  1259.                         y*mtrx->rota3.y +
  1260.                         z*mtrx->rota3.z +
  1261.                         mtrx->tran.z;
  1262.         }
  1263.         if (obj->desc->size) {
  1264.             obj->desc->size->x = mtrx->scal.x;
  1265.             obj->desc->size->y = mtrx->scal.y;
  1266.             obj->desc->size->z = mtrx->scal.z;
  1267.         }
  1268.     }
  1269.     for (obj=obj->child; obj; obj=obj->next)
  1270.         move_extr(obj, mtrx);    /* Process all children */
  1271. }
  1272.  
  1273. void OUT_MEM(s)
  1274. char *s;
  1275. {
  1276.     if (s)
  1277.     fprintf(stderr, "Ran out of memory while processing '%s'.  Sorry.\n", s);
  1278.     exit(-1);
  1279. }
  1280.  
  1281. static void malloc_arrays(i, desc)
  1282. register int i;
  1283. register DESC *desc;
  1284. {
  1285.     if (!desc->fcount) {
  1286.         desc->fcount = i;
  1287. if (!(desc->face=(UWORD*)malloc(3*desc->fcount*sizeof(UWORD))))OUT_MEM((char*)0);
  1288. if (!(desc->clst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
  1289. if (!(desc->rlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
  1290. if (!(desc->tlst=(UBYTE*)malloc(3*desc->fcount*sizeof(UBYTE))))OUT_MEM((char*)0);
  1291.         /* Initialize arrays */
  1292.         for (i=0; i<3*desc->fcount; i+=3) {
  1293.             desc->face[i]   = desc->face[i+1] = desc->face[i+2] = 0;
  1294.             desc->clst[i]   = defclst[0];
  1295.             desc->clst[i+1] = defclst[1];
  1296.             desc->clst[i+2] = defclst[2];
  1297.             desc->rlst[i]   = defrlst[0];
  1298.             desc->rlst[i+1] = defrlst[1];
  1299.             desc->rlst[i+2] = defrlst[2];
  1300.             desc->tlst[i]   = deftlst[0];
  1301.             desc->tlst[i+1] = deftlst[1];
  1302.             desc->tlst[i+2] = deftlst[2];
  1303.         }
  1304.     } else if (i != desc->fcount) {
  1305.         fprintf(stderr, "ERROR: FACE and [C|R|T]LST 'Count' values inconsistant.\n");
  1306.         OUT_MEM((char*)0);
  1307.     }
  1308. }
  1309.  
  1310. static void process_DESC(orig, world)
  1311. DESC **orig;
  1312. WORLD *world;
  1313. {
  1314.     register DESC *desc;
  1315.     register int i, j;
  1316.     char this_level[MAXLINE], name[5];
  1317.     FGRP *fgrp;
  1318.  
  1319.     if (!(desc = *orig = (DESC*)malloc(sizeof(DESC)))) { OUT_MEM("DESC"); }
  1320.     bzero((char*)desc, sizeof(DESC));
  1321.  
  1322.     /* Set up defaults: */
  1323.     defclst[0] = defclst[1] = defclst[2] = 240;    /* TS default */
  1324.     defrlst[0] = defrlst[1] = defrlst[2] = 0;
  1325.     deftlst[0] = deftlst[1] = deftlst[2] = 0;
  1326.     defspc1[0] = defspc1[1] = defspc1[2] = 0;
  1327.  
  1328.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  1329.     if (strcmp(this_level, "BEGIN") != 0) {
  1330.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'DESC'\n",
  1331.             world->cur_line);
  1332.     }
  1333.     parse_word(this_level, 0, 0);    /* No limit, original case */
  1334.  
  1335.     world->num_DESC++;
  1336.  
  1337.     while (get_line(strin, world)) {
  1338.         parse_word(name, 4, 1);        /* Get command */
  1339.         /* Put most-frequent commands near the front of this list */
  1340.         if (strcmp(name, "PNTS")==0) {
  1341.             parse_word(name, 4, 1);        /* Get field */
  1342.             if          (strcmp(name, "POIN")==0) {
  1343.                 if (!desc->pcount) {
  1344.                     fprintf(stderr, "ERROR: Line %d: 'PNTS Point' encountered before 'PNTS PCount'\n", world->cur_line);
  1345.                     OUT_MEM((char*)0);
  1346.                 }
  1347.                 i = get_UWORD();
  1348.                 if (i<0 || i>=desc->pcount) {
  1349.                     fprintf(stderr, "WARNING: Line %d: Bad index: PNTS Point[%d] should be [0..%d]\n", world->cur_line, i, desc->pcount-1);
  1350.                     continue;
  1351.                 }
  1352.                 stuff_XYZ(&desc->pnts[i]);
  1353.             } else if (strcmp(name, "PCOU")==0) {
  1354.                 if (!desc->pcount) {
  1355.                     desc->pcount = get_UWORD();
  1356.                     if (!(desc->pnts = (XYZ_st*)malloc(desc->pcount*sizeof(XYZ_st))))
  1357.                         OUT_MEM("PNTS");
  1358.                     /* Initialize array */
  1359.                     for (i=0; i<desc->pcount; i++) {
  1360.                         desc->pnts[i].x = 0;
  1361.                         desc->pnts[i].y = 0;
  1362.                         desc->pnts[i].z = 0;
  1363.                     }
  1364.                 } else {
  1365.                     fprintf(stderr, "WARNING: Line %d: PNTS Pcount defined more than once.\n", world->cur_line);
  1366.                 }
  1367.             } else {
  1368.                 if (verbose_flag)
  1369.                     fprintf(stderr, "WARNING: Line %d: Unknown PNTS field: '%s'\n",
  1370.                         world->cur_line, name);
  1371.                 continue;
  1372.             }
  1373.         } else
  1374.         if (strcmp(name, "EDGE")==0) {
  1375.             parse_word(name, 4, 1);        /* Get field */
  1376.             if          (strcmp(name, "EDGE")==0) {
  1377.                 if (!desc->ecount) {
  1378.                     fprintf(stderr, "ERROR: Line %d: 'EDGE Edge' encountered before 'EDGE ECount'\n", world->cur_line);
  1379.                     OUT_MEM((char*)0);
  1380.                 }
  1381.                 i = get_UWORD();
  1382.                 if (i<0 || i>=desc->ecount) {
  1383.                     fprintf(stderr, "WARNING: Line %d: Bad index: EDGE Edge[%d] should be [0..%d]\n", world->cur_line, i, desc->ecount-1);
  1384.                     continue;
  1385.                 }
  1386.                 desc->edge[2*i]   = get_UWORD();
  1387.                 desc->edge[2*i+1] = get_UWORD();
  1388.             } else if (strcmp(name, "ECOU")==0) {
  1389.                 if (!desc->ecount) {
  1390.                     desc->ecount = get_UWORD();
  1391.                     if (!(desc->edge = (UWORD*)malloc(2*desc->ecount*sizeof(UWORD))))
  1392.                         OUT_MEM("EDGE");
  1393.                     /* Initialize array */
  1394.                     for (i=0; i<2*desc->ecount; i++)
  1395.                         desc->edge[i] = 0;
  1396.                 } else {
  1397.                     fprintf(stderr, "WARNING: Line %d: EDGE Ecount defined more than once.\n", world->cur_line);
  1398.                 }
  1399.             } else {
  1400.                 if (verbose_flag)
  1401.                     fprintf(stderr, "WARNING: Line %d: Unknown EDGE field: '%s'\n",
  1402.                         world->cur_line, name);
  1403.                 continue;
  1404.             }
  1405.         } else
  1406.         if (strcmp(name, "EFLG")==0) {
  1407.             parse_word(name, 4, 1);        /* Get field */
  1408.             if (strcmp(name, "COUN")==0) {
  1409.                 if (!desc->eflg) {
  1410.                     if (!(desc->eflg = (EFLG*)malloc(sizeof(EFLG))))
  1411.                         OUT_MEM("EFLG");
  1412.                     desc->eflg->num = get_UWORD();
  1413.                     if (!(desc->eflg->eflg = (UBYTE*)malloc(desc->eflg->num*sizeof(UBYTE))))
  1414.                         OUT_MEM("EFLG");
  1415.                     /* Initialize array */
  1416.                     for (i=0; i<desc->eflg->num; i++)
  1417.                         desc->eflg->eflg[i] = 0;
  1418.                 } else {
  1419.                     fprintf(stderr, "WARNING: Line %d: EFLG Count defined more than once.\n", world->cur_line);
  1420.                 }
  1421.             } else if (strcmp(name, "EFLG")==0) {
  1422.                 if (!desc->eflg) {
  1423.                     fprintf(stderr, "ERROR: Line %d: 'EFLG Eflg' encountered before 'EFLG Count'\n", world->cur_line);
  1424.                     OUT_MEM((char*)0);
  1425.                 }
  1426.                 i = get_UWORD();
  1427.                 if (i<0 || i>=desc->eflg->num) {
  1428.                     fprintf(stderr, "WARNING: Line %d: Bad index: EFLG Eflg[%d] should be [0..%d]\n", world->cur_line, i, desc->eflg->num-1);
  1429.                     continue;
  1430.                 }
  1431.                 desc->eflg->eflg[i]   = get_UWORD();
  1432.             } else {
  1433.                 if (verbose_flag)
  1434.                     fprintf(stderr, "WARNING: Line %d: Unknown EFLG field: '%s'\n",
  1435.                         world->cur_line, name);
  1436.                 continue;
  1437.             }
  1438.         } else
  1439.         if (strcmp(name, "FACE")==0) {
  1440.             parse_word(name, 4, 1);        /* Get field */
  1441.             if          (strcmp(name, "CONN")==0) {
  1442.                 if (!desc->fcount) {
  1443.                     fprintf(stderr, "ERROR: Line %d: 'FACE Connects' encountered before 'FACE TCount'\n", world->cur_line);
  1444.                     OUT_MEM((char*)0);
  1445.                 }
  1446.                 i = get_UWORD();
  1447.                 if (i<0 || i>=desc->fcount) {
  1448.                     fprintf(stderr, "WARNING: Line %d: Bad index: FACE Connects[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
  1449.                     continue;
  1450.                 }
  1451.                 desc->face[3*i]   = get_UWORD();
  1452.                 desc->face[3*i+1] = get_UWORD();
  1453.                 desc->face[3*i+2] = get_UWORD();
  1454.             } else if (strcmp(name, "TCOU")==0) {
  1455.                 i = get_UWORD();
  1456.                 malloc_arrays(i, desc);
  1457.             } else {
  1458.                 if (verbose_flag)
  1459.                     fprintf(stderr, "WARNING: Line %d: Unknown FACE field: '%s'\n",
  1460.                         world->cur_line, name);
  1461.                 continue;
  1462.             }
  1463.         } else
  1464.         if (strcmp(name, "FGRP")==0) {
  1465.             parse_word(name, 4, 1);
  1466.             if (strcmp(name, "NAME")==0) {
  1467.                 if (!(fgrp = (FGRP*)malloc(sizeof(FGRP))))
  1468.                     OUT_MEM("FGRP");
  1469.                 bzero((char*)fgrp, sizeof(FGRP));
  1470.                 parse_word(ps, 0, 0);
  1471.                 strncpy(fgrp->name, ps, 18);
  1472.                 fgrp->name[18]='\0';
  1473.                 fgrp->next = desc->fgrp;
  1474.                 desc->fgrp = fgrp;
  1475.             } else if (strcmp(name, "COUN")==0) {
  1476.                 i = get_UWORD();
  1477.                 if (!desc->fgrp) {
  1478.                     fprintf(stderr, "ERROR: Line %d: 'FGRP Count' encountered before 'FGRP Name'\n", world->cur_line);
  1479.                     OUT_MEM((char*)0);
  1480.                 }
  1481.                 if (desc->fgrp->face) {
  1482.                     fprintf(stderr, "ERROR: Line %d: 'FGRP Count' encountered twice\n", world->cur_line);
  1483.                     OUT_MEM((char*)0);
  1484.                 }
  1485.                 desc->fgrp->num = i;
  1486.                 if (!(desc->fgrp->face = (UWORD*)malloc(i*sizeof(UWORD))))
  1487.                     OUT_MEM("FGRP");
  1488.                 while (i--) desc->fgrp->face[i] = 0;
  1489.             } else if (strcmp(name, "FACE")==0) {
  1490.                 i = get_UWORD();
  1491.                 if (i<0 || i>=desc->fgrp->num) {
  1492.                     fprintf(stderr, "WARNING: Line %d: Bad index: FGRP Face[%d] should be [0..%d]\n", world->cur_line, i, desc->fgrp->num-1);
  1493.                     continue;
  1494.                 }
  1495.                 desc->fgrp->face[i] = get_UWORD();
  1496.             } else {
  1497.                 if (verbose_flag)
  1498.                     fprintf(stderr, "WARNING: Line %d: Unknown FGRP field: '%s'\n",
  1499.                         world->cur_line, name);
  1500.                 continue;
  1501.             }
  1502.         } else
  1503.         if (strcmp(name, "CLST")==0) {
  1504.             parse_word(name, 4, 1);        /* Get field */
  1505.             if          (strcmp(name, "COLO")==0) {
  1506.                 if (!desc->fcount) {
  1507.                     fprintf(stderr, "ERROR: Line %d: 'CLST Color' encountered before 'CLST Count'\n", world->cur_line);
  1508.                     OUT_MEM((char*)0);
  1509.                 }
  1510.                 i = get_UWORD();
  1511.                 if (i<0 || i>=desc->fcount) {
  1512.                     fprintf(stderr, "WARNING: Line %d: Bad index: CLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
  1513.                     continue;
  1514.                 }
  1515.                 stuff_RGB((RGB_st*)&desc->clst[3*i]);    /* Place 3 UBYTE's into array */
  1516.             } else if (strcmp(name, "COUN")==0) {
  1517.                 i = get_UWORD();
  1518.                 malloc_arrays(i, desc);
  1519.             } else {
  1520.                 if (verbose_flag)
  1521.                     fprintf(stderr, "WARNING: Line %d: Unknown CLST field: '%s'\n",
  1522.                         world->cur_line, name);
  1523.                 continue;
  1524.             }
  1525.         } else
  1526.         if (strcmp(name, "RLST")==0) {
  1527.             parse_word(name, 4, 1);        /* Get field */
  1528.             if          (strcmp(name, "COLO")==0) {
  1529.                 if (!desc->fcount) {
  1530.                     fprintf(stderr, "ERROR: Line %d: 'RLST Color' encountered before 'RLST Count'\n", world->cur_line);
  1531.                     OUT_MEM((char*)0);
  1532.                 }
  1533.                 i = get_UWORD();
  1534.                 if (i<0 || i>=desc->fcount) {
  1535.                     fprintf(stderr, "WARNING: Line %d: Bad index: RLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
  1536.                     continue;
  1537.                 }
  1538.                 stuff_RGB((RGB_st*)&desc->rlst[3*i]);    /* Place three UBYTE's into array */
  1539.             } else if (strcmp(name, "COUN")==0) {
  1540.                 i = get_UWORD();
  1541.                 malloc_arrays(i, desc);
  1542.             } else {
  1543.                 if (verbose_flag)
  1544.                     fprintf(stderr, "WARNING: Line %d: Unknown RLST field: '%s'\n",
  1545.                         world->cur_line, name);
  1546.                 continue;
  1547.             }
  1548.         } else
  1549.         if (strcmp(name, "TLST")==0) {
  1550.             parse_word(name, 4, 1);        /* Get field */
  1551.             if          (strcmp(name, "COLO")==0) {
  1552.                 if (!desc->fcount) {
  1553.                     fprintf(stderr, "ERROR: Line %d: 'TLST Color' encountered before 'TLST Count'\n", world->cur_line);
  1554.                     OUT_MEM((char*)0);
  1555.                 }
  1556.                 i = get_UWORD();
  1557.                 if (i<0 || i>=desc->fcount) {
  1558.                     fprintf(stderr, "WARNING: Line %d: Bad index: TLST Color[%d] should be [0..%d]\n", world->cur_line, i, desc->fcount-1);
  1559.                     continue;
  1560.                 }
  1561.                 stuff_RGB((RGB_st*)&desc->tlst[3*i]);    /* Place three UBYTE's into array */
  1562.             } else if (strcmp(name, "COUN")==0) {
  1563.                 i = get_UWORD();
  1564.                 malloc_arrays(i, desc);
  1565.             } else {
  1566.                 if (verbose_flag)
  1567.                     fprintf(stderr, "WARNING: Line %d: Unknown TLST field: '%s'\n",
  1568.                         world->cur_line, name);
  1569.                 continue;
  1570.             }
  1571.         } else
  1572.         if (strcmp(name, "NAME")==0) {
  1573.             parse_word(ps, 0, 0);
  1574.             strncpy(desc->name, ps, 18);
  1575.             desc->name[18]='\0';
  1576.         } else
  1577.         if (strcmp(name, "SHAP")==0) {
  1578.             if (!desc->shap) {
  1579.                 if (!(desc->shap=(WORD*)malloc(2*sizeof(WORD))))
  1580.                     { OUT_MEM("SHAP"); }
  1581.                 desc->shap[0] = 2;    /* TS defaults */
  1582.                 desc->shap[1] = 0;
  1583.             }
  1584.             parse_word(name, 4, 1);        /* Get field */
  1585.             if        (strcmp(name, "SHAP")==0) desc->shap[0] = get_UWORD();
  1586.             else if (strcmp(name, "LAMP")==0) desc->shap[1] = get_UWORD();
  1587.             else {
  1588.                 if (verbose_flag)
  1589.                     fprintf(stderr, "WARNING: Line %d: Unknown SHAP field: '%s'\n",
  1590.                         world->cur_line, name);
  1591.                 continue;
  1592.             }
  1593.         } else
  1594.         if (strcmp(name, "POSI")==0) {
  1595.             if (!desc->posi) {
  1596.                 if (!(desc->posi=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1597.                     { OUT_MEM("POSI"); }
  1598.             }
  1599.             stuff_XYZ(desc->posi);
  1600.         } else
  1601.         if (strcmp(name, "AXIS")==0) {
  1602.             if (!desc->axis) {
  1603.                 if (!(desc->axis=(AXIS*)malloc(sizeof(AXIS))))
  1604.                     { OUT_MEM("AXIS"); }
  1605.                 bzero((char*)desc->axis, sizeof(AXIS));
  1606.                 desc->axis->xaxi.x = 1;
  1607.                 desc->axis->yaxi.y = 1;
  1608.                 desc->axis->zaxi.z = 1;
  1609.             }
  1610.             parse_word(name, 4, 1);        /* Get field */
  1611.             if        (strcmp(name, "XAXI")==0) stuff_XYZ(&desc->axis->xaxi);
  1612.             else if (strcmp(name, "YAXI")==0) stuff_XYZ(&desc->axis->yaxi);
  1613.             else if (strcmp(name, "ZAXI")==0) stuff_XYZ(&desc->axis->zaxi);
  1614.             else {
  1615.                 if (verbose_flag)
  1616.                     fprintf(stderr, "WARNING: Line %d: Unknown AXIS field: '%s'\n",
  1617.                         world->cur_line, name);
  1618.                 continue;
  1619.             }
  1620.         } else
  1621.         if (strcmp(name, "SIZE")==0) {
  1622.             if (!desc->size) {
  1623.                 if (!(desc->size=(XYZ_st*)malloc(sizeof(XYZ_st))))
  1624.                     { OUT_MEM("SIZE"); }
  1625.             }
  1626.             stuff_XYZ(desc->size);
  1627.         } else
  1628.         if (strcmp(name, "COLR")==0) {
  1629.             if (!desc->colr) {
  1630.                 if (!(desc->colr = (RGB_st*)malloc(sizeof(RGB_st))))
  1631.                     { OUT_MEM("COLR"); }
  1632.             }
  1633.             stuff_RGB((RGB_st*)&defclst[0]);
  1634.             desc->colr->r = defclst[0];
  1635.             desc->colr->g = defclst[1];
  1636.             desc->colr->b = defclst[2];
  1637. #ifdef DO_I_REALLY_WANT_TO_DO_THIS
  1638.             if (desc->fcount) {    /* Already initialized... rewrite */
  1639.                 for (i=3*desc->fcount; i; ) {        /* Reverse - efficiency */
  1640.                     desc->clst[--i] = defclst[2];
  1641.                     desc->clst[--i] = defclst[1];
  1642.                     desc->clst[--i] = defclst[0];
  1643.                 }
  1644.             }
  1645. #endif
  1646.         } else
  1647.         if (strcmp(name, "REFL")==0) {
  1648.             if (!desc->refl) {
  1649.                 if (!(desc->refl = (RGB_st*)malloc(sizeof(RGB_st))))
  1650.                     { OUT_MEM("REFL"); }
  1651.             }
  1652.             stuff_RGB((RGB_st*)&defrlst[0]);
  1653.             desc->refl->r = defrlst[0];
  1654.             desc->refl->g = defrlst[1];
  1655.             desc->refl->b = defrlst[2];
  1656. #ifdef DO_I_REALLY_WANT_TO_DO_THIS
  1657.             if (desc->fcount) {    /* Already initialized... rewrite */
  1658.                 for (i=3*desc->fcount; i; ) {        /* Reverse - efficiency */
  1659.                     desc->rlst[--i] = defrlst[2];
  1660.                     desc->rlst[--i] = defrlst[1];
  1661.                     desc->rlst[--i] = defrlst[0];
  1662.                 }
  1663.             }
  1664. #endif
  1665.         } else
  1666.         if (strcmp(name, "TRAN")==0) {
  1667.             if (!desc->tran) {
  1668.                 if (!(desc->tran = (RGB_st*)malloc(sizeof(RGB_st))))
  1669.                     { OUT_MEM("TRAN"); }
  1670.             }
  1671.             stuff_RGB((RGB_st*)&deftlst[0]);
  1672.             desc->tran->r = deftlst[0];
  1673.             desc->tran->g = deftlst[1];
  1674.             desc->tran->b = deftlst[2];
  1675. #ifdef DO_I_REALLY_WANT_TO_DO_THIS
  1676.             if (desc->fcount) {    /* Already initialized... rewrite */
  1677.                 for (i=3*desc->fcount; i; ) {        /* Reverse - efficiency */
  1678.                     desc->tlst[--i] = deftlst[2];
  1679.                     desc->tlst[--i] = deftlst[1];
  1680.                     desc->tlst[--i] = deftlst[0];
  1681.                 }
  1682.             }
  1683. #endif
  1684.         } else
  1685.         if (strcmp(name, "SPC1")==0) {
  1686.             if (!desc->spc1) {
  1687.                 if (!(desc->spc1 = (RGB_st*)malloc(sizeof(RGB_st))))
  1688.                     { OUT_MEM("SPC1"); }
  1689.             }
  1690.             stuff_RGB((RGB_st*)&defspc1[0]);
  1691.             desc->spc1->r = defspc1[0];
  1692.             desc->spc1->g = defspc1[1];
  1693.             desc->spc1->b = defspc1[2];
  1694.         } else
  1695.         if (strcmp(name, "TPAR")==0) {
  1696.             if (!desc->tpar) {
  1697.                 if (!(desc->tpar=(double*)malloc(16*sizeof(double))))
  1698.                     { OUT_MEM("TPAR"); }
  1699.                 bzero((char*)desc->tpar, 16*sizeof(double));
  1700.             }
  1701.             i = get_UWORD();
  1702.             if (i<0 || i>15) {
  1703.                 fprintf(stderr, "WARNING: Line %d: Bad index: TPAR[%d] should be [0..15]\n", world->cur_line, i);
  1704.                 continue;
  1705.             }
  1706.             desc->tpar[i] = get_FRACT();
  1707.         } else
  1708.         if (strcmp(name, "SURF")==0) {
  1709.             if (!desc->surf) {
  1710.                 if (!(desc->surf=(UBYTE*)malloc(5*sizeof(UBYTE))))
  1711.                     { OUT_MEM("SURF"); }
  1712.                 bzero((char*)desc->surf, 5*sizeof(UBYTE));
  1713.             }
  1714.             i = get_UWORD();
  1715.             if (i<0 || i>4) {
  1716.                 fprintf(stderr, "WARNING: Line %d: Bad index: SURF[%d] should be [0..4]\n", world->cur_line, i);
  1717.                 continue;
  1718.             }
  1719.             desc->surf[i] = get_UBYTE();
  1720.         } else
  1721.         if (strcmp(name, "MTTR")==0) {
  1722.             if (!desc->mttr) {
  1723.                 if (!(desc->mttr=(MTTR*)malloc(sizeof(MTTR))))
  1724.                     { OUT_MEM("MTTR"); }
  1725.                 bzero((char*)desc->mttr, sizeof(MTTR));
  1726.             }
  1727.             parse_word(name, 4, 1);        /* Get field */
  1728.             if        (strcmp(name, "TYPE")==0) {
  1729.                 desc->mttr->type = get_UBYTE();
  1730.                 if (desc->mttr->type>4) {
  1731.                     fprintf(stderr, "WARNING: Line %d: Invalid MTTR refraction Type %d.  Must be [0..4]\n", world->cur_line, desc->mttr->type);
  1732.                     desc->mttr->type = 0;
  1733.                     continue;
  1734.                 }
  1735.             } else if (strcmp(name, "INDE")==0) {    /* Must be between 1.0 and 3.55 inclusive */
  1736.                 desc->mttr->indx = get_FRACT();
  1737.                 if (desc->mttr->indx<1.0 || desc->mttr->indx>3.55) {
  1738.                     fprintf(stderr, "WARNING: Line %d: Invalid MTTR Index of refraction.  Must be (1.0 - 3.55)\n", world->cur_line);
  1739.                     desc->mttr->indx = 1.0;
  1740.                     continue;
  1741.                 }
  1742.             } else {
  1743.                 if (verbose_flag)
  1744.                     fprintf(stderr, "WARNING: Line %d: Unknown MTTR field: '%s'\n",
  1745.                         world->cur_line, name);
  1746.                 continue;
  1747.             }
  1748.         } else
  1749.         if (strcmp(name, "SPEC")==0) {
  1750.             if (!desc->spec) {
  1751.                 if (!(desc->spec=(UBYTE*)malloc(2*sizeof(UBYTE))))
  1752.                     { OUT_MEM("SPEC"); }
  1753.                 bzero((char*)desc->spec, 2*sizeof(UBYTE));
  1754.             }
  1755.             parse_word(name, 4, 1);        /* Get field */
  1756.             if        (strcmp(name, "SPEC")==0) desc->spec[0] = get_UBYTE();
  1757.             else if (strcmp(name, "HARD")==0) desc->spec[1] = get_UBYTE();
  1758.             else {
  1759.                 if (verbose_flag)
  1760.                     fprintf(stderr, "WARNING: Line %d: Unknown SPEC field: '%s'\n",
  1761.                         world->cur_line, name);
  1762.                 continue;
  1763.             }
  1764.         } else
  1765.         if (strcmp(name, "PRP0")==0) {
  1766.             if (!desc->prp0) {
  1767.                 if (!(desc->prp0=(UBYTE*)malloc(6*sizeof(UBYTE))))
  1768.                     { OUT_MEM("PRP0"); }
  1769.                 bzero((char*)desc->prp0, 6*sizeof(UBYTE));
  1770.                 desc->prp0[0] = 255;    /* TS defaults */
  1771.                 desc->prp0[3] = 1;
  1772.             }
  1773.             i = get_UWORD();
  1774.             if (i<0 || i>5) {
  1775.                 fprintf(stderr, "WARNING: Line %d: Bad index: PRP0[%d] should be [0..5]\n", world->cur_line, i);
  1776.                 continue;
  1777.             }
  1778.             desc->prp0[i] = get_UBYTE();
  1779.         } else
  1780.         if (strcmp(name, "PRP1")==0) {
  1781.             if (!desc->prp1) {
  1782.                 if (!(desc->prp1=(UBYTE*)malloc(8*sizeof(UBYTE))))
  1783.                     { OUT_MEM("PRP1"); }
  1784.                 bzero((char*)desc->prp1, 8*sizeof(UBYTE));
  1785.             }
  1786.             i = get_UWORD();
  1787.             if (i<0 || i>7) {
  1788.                 fprintf(stderr, "WARNING: Line %d: Bad index: PRP1[%d] should be [0..7]\n", world->cur_line, i);
  1789.                 continue;
  1790.             }
  1791.             desc->prp1[i] = get_UBYTE();
  1792.         } else
  1793.         if (strcmp(name, "TXT2")==0) {
  1794.             i = get_UWORD();
  1795.             if (i<0 || i>3) {
  1796.                 fprintf(stderr, "WARNING: Line %d: TXT2 index must be [0..3].\n",
  1797.                     world->cur_line);
  1798.                 i=3;
  1799.             }
  1800.             if (!desc->txt2[i])
  1801.                 if (!(desc->txt2[i] = (TXT2*)malloc(sizeof(TXT2))))
  1802.                     OUT_MEM("TXT2");
  1803.             parse_word(name, 4, 1);  /* get field */
  1804.             if (strcmp(name, "FLAG") == 0)
  1805.                 desc->txt2[i]->Flags = get_UWORD();
  1806.             else if (strcmp(name, "TRAN") == 0) 
  1807.                 stuff_XYZ(&desc->txt2[i]->TAxis.tran);
  1808.             else if (strcmp(name, "XAXI") == 0) 
  1809.                 stuff_XYZ(&desc->txt2[i]->TAxis.rota1);
  1810.             else if (strcmp(name, "YAXI") == 0) 
  1811.                 stuff_XYZ(&desc->txt2[i]->TAxis.rota2);
  1812.             else if (strcmp(name, "ZAXI") == 0) 
  1813.                 stuff_XYZ(&desc->txt2[i]->TAxis.rota3);
  1814.             else if (strcmp(name, "SCAL") == 0) 
  1815.                 stuff_XYZ(&desc->txt2[i]->TAxis.scal);
  1816.             else if (strcmp(name, "PARA") == 0) {
  1817.                 j = get_UWORD();
  1818.                 desc->txt2[i]->Params[j] = get_FRACT();
  1819.             } else if (strcmp(name, "PFLA") == 0) {
  1820.                 j = get_UWORD();
  1821.                 desc->txt2[i]->PFlags[j] = get_UWORD();
  1822.             } else if (strcmp(name, "SUBG") == 0) {
  1823.                 parse_word(ps, 0, 0);
  1824.                 strncpy(desc->txt2[i]->SubName, ps, 18);
  1825.                 desc->txt2[i]->SubName[18]='\0';
  1826.             } else if (strcmp(name, "TEXT") == 0)
  1827.                 parse_word(desc->txt2[i]->Name,0,0);
  1828.             else {
  1829. #ifdef WARNING
  1830.                 fprintf(stderr, "WARNING: Line %d: Unknown TXT2 field: '%s'\n",
  1831.                     world->cur_line, name);
  1832. #endif
  1833.                 continue;
  1834.             }
  1835.         } else
  1836.         if (strcmp(name, "INTS")==0) {
  1837.             if (!desc->ints) {
  1838.                 if (!(desc->ints=(double*)malloc(sizeof(double))))
  1839.                     { OUT_MEM("INTS"); }
  1840.             }
  1841.             *desc->ints = get_FRACT();
  1842.         } else
  1843.         if (strcmp(name, "INT1")==0) {
  1844.             if (!desc->int1) desc->int1=(XYZ_st*)malloc(sizeof(XYZ_st));
  1845.             if (!desc->int1) { OUT_MEM("INT1"); }
  1846.             stuff_XYZ(desc->int1);
  1847.         } else
  1848.         if (strcmp(name, "STRY")==0) {
  1849.             parse_word(name, 4, 1);        /* Get field */
  1850.             if        (strcmp(name, "PATH")==0) parse_word(desc->stry->path,18,0);
  1851.             else if (strcmp(name, "TRAN")==0) stuff_XYZ(&desc->stry->tran);
  1852.             else if (strcmp(name, "ROTA")==0) stuff_XYZ(&desc->stry->rota);
  1853.             else if (strcmp(name, "SCAL")==0) stuff_XYZ(&desc->stry->scal);
  1854.             else
  1855.             if (strcmp(name, "INFO")==0) {
  1856.                 desc->stry->info = 0;
  1857.                 while (strin[0]) {
  1858.                     parse_word(ps, 7, 1);
  1859.                     if        (strcmp(ps, "ABS_TRA")==0) desc->stry->info|=(1<<0);
  1860.                     else if (strcmp(ps, "ABS_ROT")==0) desc->stry->info|=(1<<1);
  1861.                     else if (strcmp(ps, "ABS_SCL")==0) desc->stry->info|=(1<<2);
  1862.                     else if (strcmp(ps, "LOC_TRA")==0) desc->stry->info|=(1<<4);
  1863.                     else if (strcmp(ps, "LOC_ROT")==0) desc->stry->info|=(1<<5);
  1864.                     else if (strcmp(ps, "LOC_SCL")==0) desc->stry->info|=(1<<6);
  1865.                     else if (strcmp(ps, "X_ALIGN")==0) desc->stry->info|=(1<<8);
  1866.                     else if (strcmp(ps, "Y_ALIGN")==0) desc->stry->info|=(1<<9);
  1867.                     else if (strcmp(ps, "Z_ALIGN")==0) desc->stry->info|=(1<<10);
  1868.                     else if (strcmp(ps, "FOLLOW_")==0) desc->stry->info|=(1<<12);
  1869.                     else {
  1870.                         if (verbose_flag)
  1871.                             fprintf(stderr, "WARNING: Line %d: Unknown STRY INFO flag: '%s'\n",
  1872.                                 world->cur_line, ps);
  1873.                         continue;
  1874.                     }
  1875.                 }
  1876.             } else {
  1877.                 if (verbose_flag)
  1878.                     fprintf(stderr, "WARNING: Line %d: Unknown STRY field: '%s'\n",
  1879.                         world->cur_line, name);
  1880.                 continue;
  1881.             }
  1882.         } else
  1883.         if (strcmp(name, "END")==0) {
  1884.             parse_word(name, 4, 1);
  1885.             if (strcmp(name, "DESC")!=0)
  1886.                 fprintf(stderr, "WARNING: Line %d: Expected 'END DESC' but got: 'END %s'\n", world->cur_line, name);
  1887.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  1888.             if (strcmp(this_level, ps)!=0)
  1889.                 fprintf(stderr, "WARNING: Line %d: 'DESC Begin' and 'End DESC' quoted comments do not match\n", world->cur_line);
  1890.             break;
  1891.         } else if (verbose_flag)
  1892.             fprintf(stderr, "WARNING: Line %d: Unknown DESC sub-sub-chunk: '%s'\n",
  1893.                 world->cur_line, name);
  1894.     }
  1895. }
  1896.  
  1897. /**************************************************************************/
  1898.  
  1899. /* readTistg.c - read a Textual Imagine Stage file
  1900.  *            - written by Glenn M. Lewis - 8/11/92
  1901.  *            - Imagine3 update by Rob Hounsell - Sept 94
  1902.  */
  1903.  
  1904. static void process_OSZ2();
  1905. static void process_OSIZ();
  1906. static void process_POS2();
  1907. static void process_POSN();
  1908. static void process_ALN2();
  1909. static void process_ALGN();
  1910. static void process_PALN();
  1911. static void process_TALN();
  1912. static void process_ASSC();
  1913. static void process_HING();
  1914. static void process_LYR0();
  1915. static void process_PTH2();
  1916. static void process_GLB3();
  1917. static void process_GLB2();
  1918. static void process_AXIS();
  1919. static void process_LIT2();
  1920. static void process_LITE();
  1921. static void process_FIL3();
  1922. static void process_FILE();
  1923. static void process_SPFX();
  1924. static void process_SOBJ();
  1925.  
  1926. static void process_ISTG(world)
  1927. WORLD *world;
  1928. {
  1929.     char name[5];
  1930.     char this_level[MAXLINE];
  1931.  
  1932.     if (world->istg) {
  1933.         fprintf(stderr, "Parse error: More than one ISTG chunk!\n"); exit(-1); }
  1934.     /* Allocate the ISTG structure */
  1935.     if (!(world->istg = (ISTG*)malloc(sizeof(ISTG)))) { OUT_MEM("ISTG"); }
  1936.     bzero((char*)world->istg, sizeof(ISTG));
  1937.  
  1938.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  1939.     if (strcmp(this_level, "BEGIN") != 0) {
  1940.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'ISTG'\n",
  1941.             world->cur_line);
  1942.     }
  1943.     parse_word(this_level, 0, 0);    /* No limit, original case */
  1944.  
  1945.     while (get_line(strin, world)) {
  1946.         parse_word(name, 4, 1);        /* Get command */
  1947.         if (strcmp(name, "MAXF")==0) {
  1948.             world->istg->maxf = get_UWORD();
  1949.         } else
  1950.         if (strcmp(name, "LOOP")==0) {
  1951.             world->istg->loop = get_UWORD();
  1952.         } else
  1953.         if (strcmp(name, "SOBJ")==0) {    process_SOBJ(world);
  1954.         } else if (strcmp(name, "END")==0) {
  1955.             parse_word(name, 4, 1);
  1956.             if (strcmp(name, "ISTG")!=0)
  1957.                 fprintf(stderr, "WARNING: Line %d: Expected 'END ISTG' but got: 'END %s'\n", world->cur_line, name);
  1958.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  1959.             if (strcmp(this_level, ps)!=0)
  1960.                 fprintf(stderr, "WARNING: Line %d: 'ISTG Begin' and 'End ISTG' quoted comments do not match\n", world->cur_line);
  1961.             break;
  1962.         } else {
  1963.             if (verbose_flag)
  1964.                 fprintf(stderr, "WARNING: Line %d: Unknown ISTG sub-sub-chunk: '%s'\n",
  1965.                     world->cur_line, name);
  1966.             continue;
  1967.         }
  1968.     }
  1969. /* All done. */
  1970. }
  1971.  
  1972. extern SOBJ *add_SOBJ();    /* to tail of ISTG's SOBJ list */
  1973.  
  1974. static void process_SOBJ(world)
  1975. WORLD *world;
  1976. {
  1977.     char this_level[MAXLINE], name[5];
  1978.     SOBJ *sobj;
  1979.  
  1980.     if (verbose_flag>1) fprintf(stderr, "SOBJ chunk.\n");
  1981.     parse_word(this_level, 0, 1);    /* No limit, uppercase. */
  1982.     if (strcmp(this_level, "BEGIN") != 0) {
  1983.         fprintf(stderr, "WARNING: Line %d: Bad syntax.  Missing 'Begin' after 'SOBJ'\n",
  1984.             world->cur_line);
  1985.     }
  1986.     /* Add another SOBJ to the current ISTG list */
  1987.     parse_word(this_level, 0, 0);
  1988.     sobj = add_SOBJ(world->istg);
  1989.     while (get_line(strin, world)) {
  1990.         parse_word(name, 4, 1);
  1991.         if (verbose_flag>1) fprintf(stderr, "%s chunk.\n", name);
  1992.         if (strcmp(name, "NAME")==0) {
  1993.             parse_word(ps, 0, 0);
  1994.             strncpy(sobj->name, ps, 18);
  1995.             sobj->name[18] = '\0';
  1996.         } else if (strcmp(name, "STGF")==0) { sobj->stgf = get_UWORD();
  1997.         } else if (strcmp(name, "OSZ2")==0) { process_OSZ2(sobj, world);
  1998.         } else if (strcmp(name, "OSIZ")==0) { process_OSIZ(sobj, world);
  1999.         } else if (strcmp(name, "POS2")==0) { process_POS2(sobj, world);
  2000.         } else if (strcmp(name, "POSN")==0) { process_POSN(sobj, world);
  2001.         } else if (strcmp(name, "ALN2")==0) { process_ALN2(sobj, world);
  2002.         } else if (strcmp(name, "ALGN")==0) { process_ALGN(sobj, world);
  2003.         } else if (strcmp(name, "PALN")==0) { process_PALN(sobj, world);
  2004.         } else if (strcmp(name, "TALN")==0) { process_TALN(sobj, world);
  2005.         } else if (strcmp(name, "ASSC")==0) { process_ASSC(sobj, world);
  2006.         } else if (strcmp(name, "HING")==0) { process_HING(sobj, world);
  2007.         } else if (strcmp(name, "LYR0")==0) { process_LYR0(sobj);
  2008.         } else if (strcmp(name, "PTH2")==0) { process_PTH2(sobj, world);
  2009.         } else if (strcmp(name, "GLB3")==0) { process_GLB3(sobj, world);
  2010.         } else if (strcmp(name, "GLB2")==0) { process_GLB2(sobj, world);
  2011.         } else if (strcmp(name, "AXIS")==0) { process_AXIS(sobj, world);
  2012.         } else if (strcmp(name, "LIT2")==0) { process_LIT2(sobj, world);
  2013.         } else if (strcmp(name, "LITE")==0) { process_LITE(sobj, world);
  2014.         } else if (strcmp(name, "FIL3")==0) { process_FIL3(sobj, world);
  2015.         } else if (strcmp(name, "FILE")==0) { process_FILE(sobj, world);
  2016.         } else if (strcmp(name, "SPFX")==0) { process_SPFX(sobj, world, 0);
  2017.         } else if (strcmp(name, "S2FX")==0) { process_SPFX(sobj, world, 2);
  2018.         } else if (strcmp(name, "S3FX")==0) { process_SPFX(sobj, world, 3);
  2019.         } else if (strcmp(name, "S4FX")==0) { process_SPFX(sobj, world, 4);
  2020.         } else if (strcmp(name, "END")==0) {
  2021.             parse_word(name, 4, 1);
  2022.             if (strcmp(name, "SOBJ")!=0)
  2023.                 fprintf(stderr, "WARNING: Line %d: Expected 'END SOBJ' but got: 'END %s'\n", world->cur_line, name);
  2024.             parse_word(ps, 0, 0);    /* Get the quote, if any */
  2025.             if (strcmp(this_level, ps)!=0)
  2026.                 fprintf(stderr, "WARNING: Line %d: 'SOBJ Begin' and 'End SOBJ' quoted comments do not match\n", world->cur_line);
  2027.             break;
  2028.         } else {
  2029.             if (verbose_flag)
  2030.                 fprintf(stderr, "WARNING: Line %d: Unknown SOBJ sub-sub-chunk: '%s'\n",
  2031.                     world->cur_line, name);
  2032.             continue;
  2033.         }
  2034.     }
  2035. }
  2036.  
  2037. /* Chunks unique to Imagine 2.0 */
  2038. static void process_OSIZ(sobj, world)
  2039. SOBJ *sobj;
  2040. WORLD *world;
  2041. {
  2042.     char name[5];
  2043.     register OSIZ *osiz;
  2044.  
  2045.     if (!(osiz = (OSIZ*)malloc(sizeof(OSIZ)))) OUT_MEM("OSIZ");
  2046.     bzero((char*)osiz, sizeof(OSIZ));
  2047.     osiz->chunk_type = OSIZ_CHUNK;
  2048.     osiz->start = osiz->stop = 1;
  2049.     while (1) {
  2050.         parse_word(name, 4, 1);
  2051.         if (!name[0]) break;
  2052.         if      (strcmp(name, "FLAG")==0) osiz->flags = get_UWORD();
  2053.         else if (strcmp(name, "STAR")==0) osiz->start = get_UWORD();
  2054.         else if (strcmp(name, "STOP")==0) osiz->stop  = get_UWORD();
  2055.         else if (strcmp(name, "SIZE")==0) stuff_XYZ(&osiz->size);
  2056.         else {
  2057.             if (verbose_flag)
  2058.                 fprintf(stderr, "WARNING: Line %d: Unknown OSIZ sub-sub-chunk: '%s'\n",
  2059.                     world->cur_line, name);
  2060.         }
  2061.     }
  2062.     insert_into_sorted_list((PALN**)&sobj->osiz, (PALN*)osiz);
  2063. }
  2064.  
  2065. static void process_POSN(sobj, world)
  2066. SOBJ *sobj;
  2067. WORLD *world;
  2068. {
  2069.     char name[5];
  2070.     register POSN *posn;
  2071.  
  2072.     if (!(posn = (POSN*)malloc(sizeof(POSN)))) OUT_MEM("POSN");
  2073.     bzero((char*)posn, sizeof(POSN));
  2074.     posn->chunk_type = POSN_CHUNK;
  2075.     posn->start = posn->stop = 1;
  2076.     while (1) {
  2077.         parse_word(name, 4, 1);
  2078.         if (!name[0]) break;
  2079.         if      (strcmp(name, "FLAG")==0) posn->flags = get_UWORD();
  2080.         else if (strcmp(name, "STAR")==0) posn->start = get_UWORD();
  2081.         else if (strcmp(name, "STOP")==0) posn->stop  = get_UWORD();
  2082.         else if (strcmp(name, "POSN")==0) stuff_XYZ(&posn->posn);
  2083.         else {
  2084.             if (verbose_flag)
  2085.                 fprintf(stderr, "WARNING: Line %d: Unknown POSN sub-sub-chunk: '%s'\n",
  2086.                     world->cur_line, name);
  2087.         }
  2088.     }
  2089.     insert_into_sorted_list((PALN**)&sobj->posn, (PALN*)posn);
  2090. }
  2091.  
  2092. static void process_ALGN(sobj, world)
  2093. SOBJ *sobj;
  2094. WORLD *world;
  2095. {
  2096.     char name[5];
  2097.     register ALGN *algn;
  2098.  
  2099.     if (!(algn = (ALGN*)malloc(sizeof(ALGN)))) OUT_MEM("ALGN");
  2100.     bzero((char*)algn, sizeof(ALGN));
  2101.     algn->chunk_type = ALGN_CHUNK;
  2102.     algn->start = algn->stop = 1;
  2103.     while (1) {
  2104.         parse_word(name, 4, 1);
  2105.         if (!name[0]) break;
  2106.         if      (strcmp(name, "FLAG")==0) algn->flags = get_UWORD();
  2107.         else if (strcmp(name, "STAR")==0) algn->start = get_UWORD();
  2108.         else if (strcmp(name, "STOP")==0) algn->stop  = get_UWORD();
  2109.         else if (strcmp(name, "ALGN")==0) stuff_XYZ(&algn->algn);
  2110.         else {
  2111.             if (verbose_flag)
  2112.                 fprintf(stderr, "WARNING: Line %d: Unknown ALGN sub-sub-chunk: '%s'\n",
  2113.                     world->cur_line, name);
  2114.         }
  2115.     }
  2116.     insert_into_sorted_list((PALN**)&sobj->algn, (PALN*)algn);
  2117. }
  2118.  
  2119. static void process_HING(sobj, world)
  2120. SOBJ *sobj;
  2121. WORLD *world;
  2122. {
  2123.     char name[5];
  2124.     register HING *hing;
  2125.  
  2126.     if (!(hing = (HING*)malloc(sizeof(HING)))) OUT_MEM("HING");
  2127.     bzero((char*)hing, sizeof(HING));
  2128.     hing->chunk_type = HING_CHUNK;
  2129.     hing->start = hing->stop = 1;
  2130.     while (1) {
  2131.         parse_word(name, 4, 1);
  2132.         if (!name[0]) break;
  2133.         if      (strcmp(name, "FLAG")==0) hing->flags = get_UWORD();
  2134.         else if (strcmp(name, "STAR")==0) hing->start = get_UWORD();
  2135.         else if (strcmp(name, "STOP")==0) hing->stop  = get_UWORD();
  2136.         else if (strcmp(name, "NAME")==0) {
  2137.             parse_word(hing->hingeobj, 0, 0);
  2138.         } else {
  2139.             if (verbose_flag)
  2140.                 fprintf(stderr, "WARNING: Line %d: Unknown HING sub-sub-chunk: '%s'\n",
  2141.                     world->cur_line, name);
  2142.         }
  2143.     }
  2144.     insert_into_sorted_list((PALN**)&sobj->hing, (PALN*)hing);
  2145. }
  2146.  
  2147. static void process_GLB2(sobj, world)
  2148. SOBJ *sobj;
  2149. WORLD *world;
  2150. {
  2151.     char name[128];
  2152.     register GLB2 *glb2;
  2153.  
  2154.     if (!(glb2 = (GLB2*)malloc(sizeof(GLB2)))) OUT_MEM("GLB2");
  2155.     bzero((char*)glb2, sizeof(GLB2));
  2156.     glb2->chunk_type = GLB2_CHUNK;
  2157.     glb2->start = glb2->stop = 1;
  2158.     while (1) {
  2159.         parse_word(name, 0, 1);        /* Don't limit the word size */
  2160.         if (!name[0]) break;
  2161.         if      (strncmp(name, "FLAG",4)==0) glb2->flags = get_UWORD();
  2162.         else if (strcmp(name, "START")==0) glb2->start = get_UWORD();
  2163.         else if (strcmp(name, "STOP")==0) glb2->stop  = get_UWORD();
  2164.         else if (strncmp(name, "SKY_",4)==0) glb2->sky_blending = get_ULONG();
  2165.         else if (strncmp(name, "STARF",5)==0) glb2->starfield = get_FRACT();
  2166.         else if (strncmp(name, "TRAN",4)==0) glb2->transition = get_ULONG();
  2167.         /* The following are FRACTional colors */
  2168.         else if (strncmp(name, "AMBI",4)==0) stage_RGB(&glb2->ambient);
  2169.         else if (strncmp(name, "HORI",4)==0) stage_RGB(&glb2->horizon);
  2170.         else if (strcmp(name, "ZENITH1")==0) stage_RGB(&glb2->zenith1);
  2171.         else if (strcmp(name, "ZENITH2")==0) stage_RGB(&glb2->zenith2);
  2172.         else if (strncmp(name, "FOG_C",5)==0) stage_RGB(&glb2->fog_color);
  2173.         else if (strncmp(name, "FOG_B",5)==0) glb2->fog_bottom = get_FRACT();
  2174.         else if (strncmp(name, "FOG_T",5)==0) glb2->fog_top    = get_FRACT();
  2175.         else if (strncmp(name, "FOG_L",5)==0) glb2->fog_length = get_FRACT();
  2176.         else if (strncmp(name, "BRUSH_S",7)==0) glb2->brush_seq  = get_ULONG();
  2177.         else if (strncmp(name, "BACKDROP_S",10)==0) glb2->backdrop_seq = get_ULONG();
  2178.         else if (strcmp(name, "BACKDROP")==0) {
  2179.             parse_word(glb2->backdrop, 0, 0);
  2180.         } else if (strncmp(name, "GLOB",4)==0) {
  2181.             parse_word(glb2->globalbrush, 0, 0);
  2182.         } else {
  2183.             if (verbose_flag)
  2184.                 fprintf(stderr, "WARNING: Line %d: Unknown PTH2 sub-sub-chunk: '%s'\n",
  2185.                     world->cur_line, name);
  2186.         }
  2187.     }
  2188.     insert_into_sorted_list((PALN**)&sobj->glb2, (PALN*)glb2);
  2189. }
  2190.  
  2191. static void process_LITE(sobj, world)
  2192. SOBJ *sobj;
  2193. WORLD *world;
  2194. {
  2195.     char name[5];
  2196.     register LITE *lite;
  2197.  
  2198.     if (!(lite = (LITE*)malloc(sizeof(LITE)))) OUT_MEM("LITE");
  2199.     bzero((char*)lite, sizeof(LITE));
  2200.     lite->chunk_type = LITE_CHUNK;
  2201.     lite->start = lite->stop = 1;
  2202.     while (1) {
  2203.         parse_word(name, 4, 1);
  2204.         if (!name[0]) break;
  2205.         if      (strcmp(name, "FLAG")==0) lite->flags = get_UWORD();
  2206.         else if (strcmp(name, "STAR")==0) lite->start = get_UWORD();
  2207.         else if (strcmp(name, "STOP")==0) lite->stop  = get_UWORD();
  2208.         /* The following is a FRACTional color */
  2209.         else if (strcmp(name, "COLO")==0) stage_RGB(&lite->color);
  2210.         else if (strcmp(name, "TRAN")==0) lite->transition = get_ULONG();
  2211.         else {
  2212.             if (verbose_flag)
  2213.                 fprintf(stderr, "WARNING: Line %d: Unknown LITE sub-sub-chunk: '%s'\n",
  2214.                     world->cur_line, name);
  2215.         }
  2216.     }
  2217.     insert_into_sorted_list((PALN**)&sobj->lite, (PALN*)lite);
  2218. }
  2219.  
  2220. static void process_FILE(sobj, world)
  2221. SOBJ *sobj;
  2222. WORLD *world;
  2223. {
  2224.     char name[5];
  2225.     register SFILE *file;
  2226.  
  2227.     if (!(file = (SFILE*)malloc(sizeof(SFILE)))) OUT_MEM("SFILE");
  2228.     bzero((char*)file, sizeof(SFILE));
  2229.     file->chunk_type = SFILE_CHUNK;
  2230.     file->start = file->stop = 1;
  2231.     while (1) {
  2232.         parse_word(name, 4, 1);
  2233.         if (!name[0]) break;
  2234.         if      (strcmp(name, "FLAG")==0) file->flags = get_UWORD();
  2235.         else if (strcmp(name, "STAR")==0) file->start = get_UWORD();
  2236.         else if (strcmp(name, "STOP")==0) file->stop  = get_UWORD();
  2237.         else if (strcmp(name, "CYCL")==0) file->cycles_to_perform = get_FRACT();
  2238.         else if (strcmp(name, "INIT")==0) file->initial_cycle_phase = get_FRACT();
  2239.         else if (strcmp(name, "TRAN")==0) file->transition = get_ULONG();
  2240.         else if (strcmp(name, "DESC")==0 || strcmp(name, "NAME")==0) {
  2241.             parse_word(file->object_description, 0, 0);
  2242.         } else {
  2243.             if (verbose_flag)
  2244.                 fprintf(stderr, "WARNING: Line %d: Unknown FILE sub-sub-chunk: '%s'\n",
  2245.                     world->cur_line, name);
  2246.         }
  2247.     }
  2248.     insert_into_sorted_list((PALN**)&sobj->file, (PALN*)file);
  2249. }
  2250.  
  2251. /* Chunks unique to Imagine 3.0 or common to both */
  2252. static void process_OSZ2(sobj, world)
  2253. SOBJ *sobj;
  2254. WORLD *world;
  2255. {
  2256.     char name[5];
  2257.     register OSZ2 *osz2;
  2258.  
  2259.     if (!(osz2 = (OSZ2*)malloc(sizeof(OSZ2)))) OUT_MEM("OSZ2");
  2260.     bzero((char*)osz2, sizeof(OSZ2));
  2261.     osz2->chunk_type = OSZ2_CHUNK;
  2262.     osz2->start = osz2->stop = 1;
  2263.     while (1) {
  2264.         parse_word(name, 4, 1);
  2265.         if (!name[0]) break;
  2266.         if      (strcmp(name, "FLAG")==0) osz2->flags = get_UWORD();
  2267.         else if (strcmp(name, "STAR")==0) osz2->start = get_UWORD();
  2268.         else if (strcmp(name, "STOP")==0) osz2->stop  = get_UWORD();
  2269.         else if (strcmp(name, "SIZE")==0) stuff_XYZ(&osz2->size);
  2270.         else if (strcmp(name, "VEL0")==0) osz2->vel_0 = get_FRACT();
  2271.         else if (strcmp(name, "VEL1")==0) osz2->vel_1 = get_FRACT();
  2272.         else {
  2273.             if (verbose_flag)
  2274.                 fprintf(stderr, "WARNING: Line %d: Unknown OSZ2 sub-sub-chunk: '%s'\n",
  2275.                     world->cur_line, name);
  2276.         }
  2277.     }
  2278.     insert_into_sorted_list((PALN**)&sobj->osz2, (PALN*)osz2);
  2279. }
  2280.  
  2281. static void process_POS2(sobj, world)
  2282. SOBJ *sobj;
  2283. WORLD *world;
  2284. {
  2285.     char name[5];
  2286.     register POS2 *pos2;
  2287.  
  2288.     if (!(pos2 = (POS2*)malloc(sizeof(POS2)))) OUT_MEM("POS2");
  2289.     bzero((char*)pos2, sizeof(POS2));
  2290.     pos2->chunk_type = POS2_CHUNK;
  2291.     pos2->start = pos2->stop = 1;
  2292.     while (1) {
  2293.         parse_word(name, 4, 1);
  2294.         if (!name[0]) break;
  2295.         if      (strcmp(name, "FLAG")==0) pos2->flags = get_UWORD();
  2296.         else if (strcmp(name, "STAR")==0) pos2->start = get_UWORD();
  2297.         else if (strcmp(name, "STOP")==0) pos2->stop  = get_UWORD();
  2298.         else if (strcmp(name, "POS2")==0) stuff_XYZ(&pos2->pos2);
  2299.         else if (strcmp(name, "VEL0")==0) pos2->vel_0  = get_FRACT();
  2300.         else if (strcmp(name, "VEL1")==0) pos2->vel_1  = get_FRACT();
  2301.         else {
  2302.             if (verbose_flag)
  2303.                 fprintf(stderr, "WARNING: Line %d: Unknown POS2 sub-sub-chunk: '%s'\n",
  2304.                     world->cur_line, name);
  2305.         }
  2306.     }
  2307.     insert_into_sorted_list((PALN**)&sobj->pos2, (PALN*)pos2);
  2308. }
  2309.  
  2310. static void process_ALN2(sobj, world)
  2311. SOBJ *sobj;
  2312. WORLD *world;
  2313. {
  2314.     char name[5];
  2315.     register ALN2 *aln2;
  2316.  
  2317.     if (!(aln2 = (ALN2*)malloc(sizeof(ALN2)))) OUT_MEM("ALN2");
  2318.     bzero((char*)aln2, sizeof(ALN2));
  2319.     aln2->chunk_type = ALN2_CHUNK;
  2320.     aln2->start = aln2->stop = 1;
  2321.     while (1) {
  2322.         parse_word(name, 4, 1);
  2323.         if (!name[0]) break;
  2324.         if      (strcmp(name, "FLAG")==0) aln2->flags = get_UWORD();
  2325.         else if (strcmp(name, "STAR")==0) aln2->start = get_UWORD();
  2326.         else if (strcmp(name, "STOP")==0) aln2->stop  = get_UWORD();
  2327.         else if (strcmp(name, "ALN2")==0) stuff_XYZ(&aln2->aln2);
  2328.         else if (strcmp(name, "VEL0")==0) aln2->vel_0  = get_FRACT();
  2329.         else if (strcmp(name, "VEL1")==0) aln2->vel_1  = get_FRACT();
  2330.         else {
  2331.             if (verbose_flag)
  2332.                 fprintf(stderr, "WARNING: Line %d: Unknown ALN2 sub-sub-chunk: '%s'\n",
  2333.                     world->cur_line, name);
  2334.         }
  2335.     }
  2336.     insert_into_sorted_list((PALN**)&sobj->aln2, (PALN*)aln2);
  2337. }
  2338.  
  2339. static void process_PALN(sobj, world)
  2340. SOBJ *sobj;
  2341. WORLD *world;
  2342. {
  2343.     char name[5];
  2344.     register PALN *paln;
  2345.  
  2346.     if (!(paln = (PALN*)malloc(sizeof(PALN)))) OUT_MEM("PALN");
  2347.     bzero((char*)paln, sizeof(PALN));
  2348.     paln->chunk_type = PALN_CHUNK;
  2349.     paln->start = paln->stop = 1;
  2350.     while (1) {
  2351.         parse_word(name, 4, 1);
  2352.         if (!name[0]) break;
  2353.         if      (strcmp(name, "FLAG")==0) paln->flags = get_UWORD();
  2354.         else if (strcmp(name, "STAR")==0) paln->start = get_UWORD();
  2355.         else if (strcmp(name, "STOP")==0) paln->stop  = get_UWORD();
  2356.         else {
  2357.             if (verbose_flag)
  2358.                 fprintf(stderr, "WARNING: Line %d: Unknown PALN sub-sub-chunk: '%s'\n",
  2359.                     world->cur_line, name);
  2360.         }
  2361.     }
  2362.     insert_into_sorted_list(&sobj->aln2, paln);
  2363. }
  2364.  
  2365. static void process_TALN(sobj, world)
  2366. SOBJ *sobj;
  2367. WORLD *world;
  2368. {
  2369.     char name[5];
  2370.     register TALN *taln;
  2371.  
  2372.     if (!(taln = (TALN*)malloc(sizeof(TALN)))) OUT_MEM("TALN");
  2373.     bzero((char*)taln, sizeof(TALN));
  2374.     taln->chunk_type = TALN_CHUNK;
  2375.     taln->start = taln->stop = 1;
  2376.     while (1) {
  2377.         parse_word(name, 4, 1);
  2378.         if (!name[0]) break;
  2379.         if      (strcmp(name, "FLAG")==0) taln->flags = get_UWORD();
  2380.         else if (strcmp(name, "STAR")==0) taln->start = get_UWORD();
  2381.         else if (strcmp(name, "STOP")==0) taln->stop  = get_UWORD();
  2382.         else if (strcmp(name, "INIT")==0) taln->initial_y = get_FRACT();
  2383.         else if (strcmp(name, "FINA")==0) taln->final_y   = get_FRACT();
  2384.         else if (strcmp(name, "TRAC")==0 || strcmp(name, "NAME")==0 ||
  2385.             strcmp(name, "OBJE")==0) {
  2386.             parse_word(taln->trackobj, 0, 0);
  2387.         } else {
  2388.             if (verbose_flag)
  2389.                 fprintf(stderr, "WARNING: Line %d: Unknown TALN sub-sub-chunk: '%s'\n",
  2390.                     world->cur_line, name);
  2391.         }
  2392.     }
  2393.     insert_into_sorted_list((PALN**)&sobj->aln2, (PALN*)taln);
  2394. }
  2395.  
  2396. static void process_ASSC(sobj, world)
  2397. SOBJ *sobj;
  2398. WORLD *world;
  2399. {
  2400.     char name[5];
  2401.     register ASSC *assc;
  2402.  
  2403.     if (!(assc = (ASSC*)malloc(sizeof(ASSC)))) OUT_MEM("ASSC");
  2404.     bzero((char*)assc, sizeof(assc));
  2405.     assc->chunk_type = ASSC_CHUNK;
  2406.     assc->start = assc->stop = 1;
  2407.     while (1) {
  2408.         parse_word(name, 4, 1);
  2409.         if (!name[0]) break;
  2410.         if      (strcmp(name, "FLAG")==0) assc->flags = get_UWORD();
  2411.         else if (strcmp(name, "STAR")==0) assc->start = get_UWORD();
  2412.         else if (strcmp(name, "STOP")==0) assc->stop  = get_UWORD();
  2413.         else if (strcmp(name, "NAME")==0) {
  2414.             parse_word(assc->assc_obj, 0, 0);
  2415.         } else {
  2416.             if (verbose_flag)
  2417.                 fprintf(stderr, "WARNING: Line %d: Unknown ASSC sub-sub-chunk: '%s'\n",
  2418.                     world->cur_line, name);
  2419.         }
  2420.     }
  2421.     insert_into_sorted_list((PALN**)&sobj->assc, (PALN*)assc);
  2422. }
  2423.  
  2424. static void process_LYR0(sobj)
  2425. SOBJ *sobj;
  2426. {
  2427.     register LYR0 *lyr0;
  2428.  
  2429.     if (!(lyr0 = (LYR0*)malloc(sizeof(LYR0)))) OUT_MEM("LYR0");
  2430.     bzero((char*)lyr0, sizeof(LYR0));
  2431.     lyr0->chunk_type = LYR0_CHUNK;
  2432.     lyr0->layer = get_UWORD();
  2433.     insert_into_sorted_list((PALN**)&sobj->lyr0, (PALN*)lyr0);
  2434. }
  2435.  
  2436. static void process_PTH2(sobj, world)
  2437. SOBJ *sobj;
  2438. WORLD *world;
  2439. {
  2440.     char name[128];
  2441.     register PTH2 *pth2;
  2442.  
  2443.     if (!(pth2 = (PTH2*)malloc(sizeof(PTH2)))) OUT_MEM("PTH2");
  2444.     bzero((char*)pth2, sizeof(PTH2));
  2445.     pth2->chunk_type = PTH2_CHUNK;
  2446.     pth2->start = pth2->stop = 1;
  2447.     while (1) {
  2448.         parse_word(name, 0, 1);        /* Don't limit the word size */
  2449.         if (!name[0]) break;
  2450.         if      (strncmp(name, "FLAG",4)==0) pth2->flags = get_UWORD();
  2451.         else if (strcmp(name, "START")==0) pth2->start = get_UWORD();
  2452.         else if (strncmp(name, "STOP",4)==0) pth2->stop  = get_UWORD();
  2453.         else if (strncmp(name, "ACCE",4)==0) pth2->acceleration_frames = get_ULONG();
  2454.         else if (strncmp(name, "START_",6)==0) pth2->start_speed=get_FRACT();
  2455.         else if (strncmp(name, "DECEL",5)==0) pth2->deacceleration_frames = get_ULONG();
  2456.         else if (strncmp(name, "END_",4)==0) pth2->end_speed = get_FRACT();
  2457.         else if (strcmp(name, "PATH")==0 || strcmp(name, "NAME")==0) {
  2458.             parse_word(pth2->path, 0, 0);
  2459.         } else {
  2460.             if (verbose_flag)
  2461.                 fprintf(stderr, "WARNING: Line %d: Unknown PTH2 sub-sub-chunk: '%s'\n",
  2462.                     world->cur_line, name);
  2463.         }
  2464.     }
  2465.     insert_into_sorted_list((PALN**)&sobj->pos2, (PALN*)pth2);
  2466. }
  2467.  
  2468. static void process_GLB3(sobj, world)
  2469. SOBJ *sobj;
  2470. WORLD *world;
  2471. {
  2472.     char name[128];
  2473.     register GLB3 *glb3;
  2474.  
  2475.     if (!(glb3 = (GLB3*)malloc(sizeof(GLB3)))) OUT_MEM("GLB3");
  2476.     bzero((char*)glb3, sizeof(GLB3));
  2477.     glb3->chunk_type = GLB3_CHUNK;
  2478.     glb3->start = glb3->stop = 1;
  2479.     while (1) {
  2480.         parse_word(name, 0, 1);        /* Don't limit the word size */
  2481.         if (!name[0]) break;
  2482.         if      (strncmp(name, "FLAG",4)==0) glb3->flags = get_UWORD();
  2483.         else if (strcmp(name, "START")==0) glb3->start = get_UWORD();
  2484.         else if (strcmp(name, "STOP")==0) glb3->stop  = get_UWORD();
  2485.         else if (strncmp(name, "STARF",5)==0) glb3->starfield = get_FRACT();
  2486.         else if (strncmp(name, "TRAN",4)==0) glb3->transition = get_ULONG();
  2487.         /* The following are FRACTional colors */
  2488.         else if (strncmp(name, "AMBI",4)==0) stage_RGB(&glb3->ambient);
  2489.         else if (strncmp(name, "HORI",4)==0) stage_RGB(&glb3->horizon);
  2490.         else if (strcmp(name, "ZENITH1")==0) stage_RGB(&glb3->zenith1);
  2491.         else if (strcmp(name, "ZENITH2")==0) stage_RGB(&glb3->zenith2);
  2492.         else if (strncmp(name, "FOG_C",5)==0) stage_RGB(&glb3->fog_color);
  2493.         else if (strncmp(name, "FOG_B",5)==0) glb3->fog_bottom = get_FRACT();
  2494.         else if (strncmp(name, "FOG_T",5)==0) glb3->fog_top    = get_FRACT();
  2495.         else if (strncmp(name, "FOG_L",5)==0) glb3->fog_length = get_FRACT();
  2496.         else if (strncmp(name, "BRUSH_S",7)==0) glb3->brush_seq  = get_ULONG();
  2497.         else if (strncmp(name, "BACKDROP_S",10)==0) glb3->backdrop_seq = get_ULONG();
  2498.         else if (strcmp(name, "BACKDROP")==0) {
  2499.             parse_word(glb3->backdrop, 0, 0);
  2500.         } else if (strncmp(name, "GLOB",4)==0) {
  2501.             parse_word(glb3->globalbrush, 0, 0);
  2502.         } else {
  2503.             if (verbose_flag)
  2504.                 fprintf(stderr, "WARNING: Line %d: Unknown GLB3 sub-sub-chunk: '%s'\n",
  2505.                     world->cur_line, name);
  2506.         }
  2507.     }
  2508.     insert_into_sorted_list((PALN**)&sobj->glb3, (PALN*)glb3);
  2509. }
  2510.  
  2511. static void process_AXIS(sobj, world)
  2512. SOBJ *sobj;
  2513. WORLD *world;
  2514. {
  2515.     char name[5];
  2516.     register SAXIS *axis;
  2517.  
  2518.     if (!(axis = (SAXIS*)malloc(sizeof(SAXIS)))) OUT_MEM("SAXIS");
  2519.     bzero((char*)axis, sizeof(SAXIS));
  2520.     axis->chunk_type = SAXIS_CHUNK;
  2521.     axis->start = axis->stop = 1;
  2522.     while (1) {
  2523.         parse_word(name, 4, 1);
  2524.         if (!name[0]) break;
  2525.         if      (strcmp(name, "FLAG")==0) axis->flags = get_UWORD();
  2526.         else if (strcmp(name, "STAR")==0) axis->start = get_UWORD();
  2527.         else if (strcmp(name, "STOP")==0) axis->stop  = get_UWORD();
  2528.         else {
  2529.             if (verbose_flag)
  2530.                 fprintf(stderr, "WARNING: Line %d: Unknown AXIS sub-sub-chunk: '%s'\n",
  2531.                     world->cur_line, name);
  2532.         }
  2533.     }
  2534.     insert_into_sorted_list((PALN**)&sobj->axis, (PALN*)axis);
  2535. }
  2536.  
  2537. static void process_LIT2(sobj, world)
  2538. SOBJ *sobj;
  2539. WORLD *world;
  2540. {
  2541.     char name[5];
  2542.     register LIT2 *lit2;
  2543.  
  2544.     if (!(lit2 = (LIT2*)malloc(sizeof(LIT2)))) OUT_MEM("LIT2");
  2545.     bzero((char*)lit2, sizeof(LIT2));
  2546.     lit2->chunk_type = LIT2_CHUNK;
  2547.     lit2->start = lit2->stop = 1;
  2548.     while (1) {
  2549.         parse_word(name, 4, 1);
  2550.         if (!name[0]) break;
  2551.         if      (strcmp(name, "FLAG")==0) lit2->flags = get_UWORD();
  2552.         else if (strcmp(name, "STAR")==0) lit2->start = get_UWORD();
  2553.         else if (strcmp(name, "STOP")==0) lit2->stop  = get_UWORD();
  2554.         /* The following is a FRACTional color */
  2555.         else if (strcmp(name, "COLO")==0) stage_RGB(&lit2->color);
  2556.         else if (strcmp(name, "TRAN")==0) lit2->transition = get_ULONG();
  2557.         else {
  2558.             if (verbose_flag)
  2559.                 fprintf(stderr, "WARNING: Line %d: Unknown LIT2 sub-sub-chunk: '%s'\n",
  2560.                     world->cur_line, name);
  2561.         }
  2562.     }
  2563.     insert_into_sorted_list((PALN**)&sobj->lit2, (PALN*)lit2);
  2564. }
  2565.  
  2566. static void process_FIL3(sobj, world)
  2567. SOBJ *sobj;
  2568. WORLD *world;
  2569. {
  2570.     char name[5];
  2571.     register FIL3 *fil3;
  2572.  
  2573.     if (!(fil3 = (FIL3*)malloc(sizeof(FIL3)))) OUT_MEM("FIL3");
  2574.     bzero((char*)fil3, sizeof(FIL3));
  2575.     fil3->chunk_type = FIL3_CHUNK;
  2576.     fil3->start = fil3->stop = 1;
  2577.     while (1) {
  2578.         parse_word(name, 4, 1);
  2579.         if (!name[0]) break;
  2580.         if      (strcmp(name, "FLAG")==0) fil3->flags = get_UWORD();
  2581.         else if (strcmp(name, "STAR")==0) fil3->start = get_UWORD();
  2582.         else if (strcmp(name, "STOP")==0) fil3->stop  = get_UWORD();
  2583.         else if (strcmp(name, "CYCL")==0) fil3->cycles_to_perform = get_FRACT();
  2584.         else if (strcmp(name, "INIT")==0) fil3->initial_cycle_phase = get_FRACT();
  2585.         else if (strcmp(name, "VEL0")==0) fil3->vel_0  = get_FRACT();
  2586.         else if (strcmp(name, "VEL1")==0) fil3->vel_1  = get_FRACT();
  2587.     else if (strcmp(name, "STAT")==0) parse_word(fil3->state, 0, 0);
  2588.     else if (strcmp(name, "DESC")==0 || strcmp(name, "NAME")==0) {
  2589.             parse_word(fil3->object_description, 0, 0);
  2590.         } else {
  2591.             if (verbose_flag)
  2592.                 fprintf(stderr, "WARNING: Line %d: Unknown FIL3 sub-sub-chunk: '%s'\n",
  2593.                     world->cur_line, name);
  2594.         }
  2595.     }
  2596.     insert_into_sorted_list((PALN**)&sobj->fil3, (PALN*)fil3);
  2597. }
  2598.  
  2599. static void process_SPFX(sobj, world, index)
  2600. SOBJ *sobj;
  2601. WORLD *world;
  2602. int index;
  2603. {
  2604.     char name[5];
  2605.     register SPFX *spfx;
  2606.  
  2607.     if (!(spfx = (SPFX*)malloc(sizeof(SPFX)))) OUT_MEM("SPFX");
  2608.     bzero((char*)spfx, sizeof(SPFX));
  2609.     spfx->chunk_type = SPFX_CHUNK;
  2610.     spfx->start = spfx->stop = 1;
  2611.     while (1) {
  2612.         parse_word(name, 4, 1);
  2613.         if (!name[0]) break;
  2614.         if      (strcmp(name, "FLAG")==0) spfx->flags = get_UWORD();
  2615.         else if (strcmp(name, "STAR")==0) spfx->start = get_UWORD();
  2616.         else if (strcmp(name, "STOP")==0) spfx->stop  = get_UWORD();
  2617.     else if (strcmp(name, "NAME")==0) {
  2618.             parse_word(spfx->effect, 0, 0);
  2619.         }
  2620.         else if (strcmp(name, "DATA")==0) {
  2621.             parse_effect_data(spfx->effect_data);
  2622.         } else {
  2623.             if (verbose_flag)
  2624.                 fprintf(stderr, "WARNING: Line %d: Unknown FIL3 sub-sub-chunk: '%s'\n",
  2625.                     world->cur_line, name);
  2626.         }
  2627.     }
  2628.     switch (index) {
  2629.         case 0:
  2630.             insert_into_sorted_list((PALN**)&sobj->spfx, (PALN*)spfx);
  2631.             break;
  2632.         case 2:
  2633.             insert_into_sorted_list((PALN**)&sobj->s2fx, (PALN*)spfx);
  2634.             break;
  2635.         case 3:
  2636.             insert_into_sorted_list((PALN**)&sobj->s3fx, (PALN*)spfx);
  2637.             break;
  2638.         case 4:
  2639.             insert_into_sorted_list((PALN**)&sobj->s4fx, (PALN*)spfx);
  2640.     }
  2641. }
  2642.  
  2643.